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 diff --git a/.github/composite-actions/build-babelfishpg_unit/action.yml b/.github/composite-actions/build-babelfishpg_unit/action.yml new file mode 100644 index 0000000000..959653fde7 --- /dev/null +++ b/.github/composite-actions/build-babelfishpg_unit/action.yml @@ -0,0 +1,27 @@ +name: 'Build babelfishpg_unit' +inputs: + install_dir: + description: 'Engine install directory' + required: no + default: psql + extension_branch: + description: 'Extension Branch name which needs to checkout first' + required: no + default: 'latest' + +runs: + using: "composite" + steps: + - if: always() && (inputs.extension_branch == 'latest') + uses: actions/checkout@v2 + + - name: Build babelfishpg_unit + run: | + export PG_CONFIG=~/${{ inputs.install_dir }}/bin/pg_config + export PG_SRC=~/work/babelfish_extensions/postgresql_modified_for_babelfish + export cmake=$(which cmake) + export PATH=~/${{ inputs.install_dir }}/bin:$PATH + cd contrib/babelfishpg_unit + make clean && make && make install + shell: bash + \ No newline at end of file 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/.github/composite-actions/build-modified-postgres/action.yml b/.github/composite-actions/build-modified-postgres/action.yml index 25b9c5df56..06baec2d30 100644 --- a/.github/composite-actions/build-modified-postgres/action.yml +++ b/.github/composite-actions/build-modified-postgres/action.yml @@ -59,7 +59,7 @@ runs: elif [[ ${{inputs.engine_branch}} != *"__PG_13_"* ]]; then cd ../.. rm -rf pg_hint_plan - git clone --depth 1 --branch PG15 https://github.com/ossc-db/pg_hint_plan.git + git clone --depth 1 --branch REL15_1_5_1 https://github.com/ossc-db/pg_hint_plan.git cd pg_hint_plan export PATH=$HOME/${{ inputs.install_dir }}/bin:$PATH make diff --git a/.github/composite-actions/dump-restore-util/action.yml b/.github/composite-actions/dump-restore-util/action.yml index 689c3f908e..4437a92d93 100644 --- a/.github/composite-actions/dump-restore-util/action.yml +++ b/.github/composite-actions/dump-restore-util/action.yml @@ -18,6 +18,17 @@ 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' + dump_data_as: + description: "Dump table data using COPY or INSERT" + required: false + default: 'copy' + dump_format: + description: "Dump format (plain/custom/tar/directory)" + required: true runs: using: "composite" @@ -39,54 +50,44 @@ 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 + export PGPASSWORD=12345678 + + if [[ '${{ inputs.dump_data_as }}' == 'inserts' ]];then + export DUMP_OPTS='--column-inserts' + else + export DUMP_OPTS='' + fi + export DUMP_OPTS="$DUMP_OPTS --format=${{ inputs.dump_format }}" + + if [[ '${{ inputs.logical_database }}' == 'null' ]];then + echo 'Starting to dump whole Babelfish physical database' + ~/${{ inputs.pg_new_dir }}/bin/pg_dumpall -h localhost --database jdbc_testdb --username jdbc_user --roles-only --quote-all-identifiers --verbose --no-role-passwords -f pg_dump_globals.sql 2>>error.log + ~/${{ inputs.pg_new_dir }}/bin/pg_dump -h localhost --username jdbc_user $DUMP_OPTS --quote-all-identifiers --verbose --file="pg_dump.archive" --dbname=jdbc_testdb 2>>error.log + else + echo "Starting to dump Babelfish logical database ${{ inputs.logical_database }}" + ~/${{ inputs.pg_new_dir }}/bin/pg_dumpall -h localhost --database jdbc_testdb --username jdbc_user --roles-only --quote-all-identifiers --verbose --no-role-passwords --bbf-database-name='${{ inputs.logical_database }}' -f pg_dump_globals.sql 2>>error.log + ~/${{ inputs.pg_new_dir }}/bin/pg_dump -h localhost --username jdbc_user $DUMP_OPTS --quote-all-identifiers --verbose --bbf-database-name='${{ inputs.logical_database }}' --file="pg_dump.archive" --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;" - 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 + echo 'Database dump complete.' - # Temporary step - - name: Temporarily disable failing tests - if: always() && steps.run-pg_dump-restore.outcome == 'success' && inputs.is_final_ver == 'true' - env: - migr_mode: ${{ inputs.migration_mode }} - run: | - if [[ "$migr_mode" == "multi-db" ]];then - base_dir=${{ matrix.upgrade-path.path[0] }} - if [[ "$base_dir" == *"latest"* ]]; then - base_dir="latest" - fi + # Create and initialise Babelfish extensions in the new server to perform restore. + 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 PGPASSWORD=12345678 ~/${{ inputs.pg_new_dir }}/bin/psql -h localhost -d jdbc_testdb -U jdbc_user --single-transaction -f ~/upgrade/pg_dump_globals.sql 2>> ~/upgrade/error.log + echo 'Restoring from pg_dump' + if [[ '${{ inputs.dump_format }}' == 'plain' ]];then + sudo PGPASSWORD=12345678 ~/${{ inputs.pg_new_dir }}/bin/psql -h localhost -d jdbc_testdb -U jdbc_user --single-transaction -f ~/upgrade/pg_dump.archive 2>> ~/upgrade/error.log else - base_dir="singledb" + ~/${{ inputs.pg_new_dir }}/bin/pg_restore -h localhost -d jdbc_testdb -U jdbc_user --single-transaction ~/upgrade/pg_dump.archive 2>> ~/upgrade/error.log 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 "/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 - 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 + export PATH=/opt/mssql-tools/bin:$PATH + sqlcmd -S localhost -U jdbc_user -P 12345678 -Q "SELECT @@version GO" shell: bash - name: Run Verify Tests @@ -95,4 +96,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/install-extensions/action.yml b/.github/composite-actions/install-extensions/action.yml index 74f9a43d44..e49e30e6ac 100644 --- a/.github/composite-actions/install-extensions/action.yml +++ b/.github/composite-actions/install-extensions/action.yml @@ -9,6 +9,10 @@ inputs: description: 'Database migration mode' required: no default: "single-db" + parallel_query_mode: + description: 'Postgres Parallel Query Mode' + required: no + default: false runs: using: "composite" @@ -21,11 +25,19 @@ runs: ~/${{inputs.install_dir}}/bin/pg_ctl -D ~/${{inputs.install_dir}}/data/ -l logfile start cd ${{inputs.install_dir}}/data sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" postgresql.conf - sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds'/g" postgresql.conf + sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds, pg_stat_statements'/g" postgresql.conf ipaddress=$(ifconfig eth0 | grep 'inet ' | cut -d: -f2 | awk '{ print $2}') - sudo echo "host all all $ipaddress/32 trust" >> pg_hba.conf + # Allow only runner to have trust authentication, all other users must provide a password + { + sudo echo "local all runner trust" + sudo echo "local all all md5" + sudo echo "host all runner 127.0.0.1/32 trust" + sudo echo "host all runner $ipaddress/32 trust" + sudo echo "host all all 0.0.0.0/0 md5" + sudo echo "host all all ::/0 md5" + } > pg_hba.conf ~/${{inputs.install_dir}}/bin/pg_ctl -D ~/${{inputs.install_dir}}/data/ -l logfile restart cd ~/work/babelfish_extensions/babelfish_extensions/ - sudo ~/${{inputs.install_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 + sudo ~/${{inputs.install_dir}}/bin/psql -d postgres -U runner -v user="jdbc_user" -v db="jdbc_testdb" -v migration_mode=${{inputs.migration_mode}} -v parallel_query_mode=${{inputs.parallel_query_mode}} -f .github/scripts/create_extension.sql sqlcmd -S localhost -U "jdbc_user" -P 12345678 -Q "SELECT @@version GO" shell: bash diff --git a/.github/composite-actions/minor-version-upgrade-util/action.yml b/.github/composite-actions/minor-version-upgrade-util/action.yml index 3ebda20825..57bcc60de6 100644 --- a/.github/composite-actions/minor-version-upgrade-util/action.yml +++ b/.github/composite-actions/minor-version-upgrade-util/action.yml @@ -77,6 +77,4 @@ runs: done export scheduleFile=upgrade/$base_dir/schedule mvn test - shell: bash - - \ No newline at end of file + shell: bash 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..dfc4e3e96e 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" @@ -65,9 +69,17 @@ runs: ~/${{ inputs.install_dir }}/bin/pg_ctl -D ~/${{ inputs.install_dir }}/data/ -l logfile start cd ${{ inputs.install_dir }}/data sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" postgresql.conf - sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds'/g" postgresql.conf + sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds, pg_stat_statements'/g" postgresql.conf ipaddress=$(ifconfig eth0 | grep 'inet ' | cut -d: -f2 | awk '{ print $2}') - sudo echo "host all all $ipaddress/32 trust" >> pg_hba.conf + # Allow only runner to have trust authentication, all other users must provide a password + { + sudo echo "local all runner trust" + sudo echo "local all all md5" + sudo echo "host all runner 127.0.0.1/32 trust" + sudo echo "host all runner $ipaddress/32 trust" + sudo echo "host all all 0.0.0.0/0 md5" + sudo echo "host all all ::/0 md5" + } > pg_hba.conf ~/${{ inputs.install_dir }}/bin/pg_ctl -D ~/${{ inputs.install_dir }}/data/ -l logfile restart sudo ~/${{ inputs.install_dir }}/bin/psql -d postgres -U runner -c "CREATE USER jdbc_user WITH SUPERUSER CREATEDB CREATEROLE PASSWORD '12345678' INHERIT;" sudo ~/${{ inputs.install_dir }}/bin/psql -d postgres -U runner -c "DROP DATABASE IF EXISTS jdbc_testdb;" @@ -111,6 +123,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 +147,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..e76a5e1d06 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,19 @@ 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) + dump_data_as_var=".\"dump-restore-version\"[${{ matrix.upgrade-path.id }}][$i].\"dump-data-as\"" + dump_data_as=$(yq $dump_data_as_var ${{ github.workspace }}/.github/configuration/dump-restore-test-configuration.yml) + dump_format_var=".\"dump-restore-version\"[${{ matrix.upgrade-path.id }}][$i].\"dump-format\"" + dump_format=$(yq $dump_format_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 dump_data_as: ${dump_data_as}\n dump_format: ${dump_format}\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 dump_data_as: ${dump_data_as}\n dump_format: ${dump_format}\n\n" >> $dump_restore_version_dir_path/action.yml + fi previous_installed_version=$dump_restore_version done diff --git a/.github/composite-actions/setup-new-version/action.yml b/.github/composite-actions/setup-new-version/action.yml index 88222b64c8..9118cb15d8 100644 --- a/.github/composite-actions/setup-new-version/action.yml +++ b/.github/composite-actions/setup-new-version/action.yml @@ -52,7 +52,15 @@ runs: ~/${{ inputs.pg_new_dir }}/bin/initdb -D ~/${{ inputs.pg_new_dir }}/data cd ~/${{ inputs.pg_new_dir }}/data sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" postgresql.conf - sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds'/g" postgresql.conf + sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds, pg_stat_statements'/g" postgresql.conf ipaddress=$(ifconfig eth0 | grep 'inet ' | cut -d: -f2 | awk '{ print $2}') - sudo echo "host all all $ipaddress/32 trust" >> pg_hba.conf + # Allow only runner to have trust authentication, all other users must provide a password + { + sudo echo "local all runner trust" + sudo echo "local all all md5" + sudo echo "host all runner 127.0.0.1/32 trust" + sudo echo "host all runner $ipaddress/32 trust" + sudo echo "host all all 0.0.0.0/0 md5" + sudo echo "host all all ::/0 md5" + } > pg_hba.conf shell: bash diff --git a/.github/configuration/dump-restore-test-configuration.yml b/.github/configuration/dump-restore-test-configuration.yml index ced988327c..ad36e0e00e 100644 --- a/.github/configuration/dump-restore-test-configuration.yml +++ b/.github/configuration/dump-restore-test-configuration.yml @@ -1,8 +1,70 @@ dump-restore-version: [[ { - version: source.latest + version: source.latest, + dump-data-as: copy, + dump-format: plain, + logical-database: null }, - { - version: target.latest + { + version: target.latest, + dump-data-as: copy, + dump-format: plain, + logical-database: null + } +], +[ + { + version: source.latest, + dump-data-as: copy, + dump-format: custom, + logical-database: master + }, + { + version: target.latest, + dump-data-as: copy, + dump-format: custom, + logical-database: master + } +], +[ + { + version: source.latest, + dump-data-as: inserts, + dump-format: tar, + logical-database: null + }, + { + version: target.latest, + dump-data-as: inserts, + dump-format: tar, + logical-database: null + } +], +[ + { + version: source.latest, + dump-data-as: inserts, + dump-format: directory, + logical-database: master + }, + { + version: target.latest, + dump-data-as: inserts, + dump-format: directory, + logical-database: master + } +], +[ + { + version: source.latest, + dump-data-as: copy, + dump-format: plain, + logical-database: database_1 + }, + { + version: target.latest, + dump-data-as: copy, + dump-format: plain, + logical-database: database_1 } ]] diff --git a/.github/configuration/upgrade-test-configuration.yml b/.github/configuration/upgrade-test-configuration.yml index a91445b734..c4f427795f 100644 --- a/.github/configuration/upgrade-test-configuration.yml +++ b/.github/configuration/upgrade-test-configuration.yml @@ -76,7 +76,17 @@ upgrade-version: [[ ], [ { - version: 14.8, + version: '14.10', + upgrade-type: null + }, + { + version: target.latest, + upgrade-type: major + } +], +[ + { + version: '14.11', upgrade-type: null }, { @@ -89,6 +99,16 @@ upgrade-version: [[ version: 15.2, upgrade-type: null }, + { + version: target.latest, + upgrade-type: minor + } +], +[ + { + version: 15.5, + upgrade-type: null + }, { version: target.latest, upgrade-type: minor diff --git a/.github/scripts/create_extension.sql b/.github/scripts/create_extension.sql index 1849f88b28..2b8c18449e 100644 --- a/.github/scripts/create_extension.sql +++ b/.github/scripts/create_extension.sql @@ -8,5 +8,15 @@ GRANT ALL ON SCHEMA sys to :user; ALTER USER :user CREATEDB; ALTER SYSTEM SET babelfishpg_tsql.database_name = :db; ALTER SYSTEM SET babelfishpg_tsql.migration_mode = :'migration_mode'; + +\if :parallel_query_mode + ALTER SYSTEM SET parallel_setup_cost = 0; + ALTER SYSTEM SET parallel_tuple_cost = 0; + ALTER SYSTEM SET min_parallel_index_scan_size = 0; + ALTER SYSTEM SET min_parallel_table_scan_size = 0; + ALTER SYSTEM SET force_parallel_mode = 1; + ALTER SYSTEM SET max_parallel_workers_per_gather = 4; +\endif + SELECT pg_reload_conf(); CALL SYS.INITIALIZE_BABELFISH(:'user'); diff --git a/.github/scripts/unit_tests.sql b/.github/scripts/unit_tests.sql new file mode 100644 index 0000000000..2aba9256a7 --- /dev/null +++ b/.github/scripts/unit_tests.sql @@ -0,0 +1,3 @@ +CREATE EXTENSION IF NOT EXISTS babelfishpg_unit; + +SELECT * FROM babelfishpg_unit.babelfishpg_unit_run_tests(); diff --git a/.github/template/version-branch-template.yml b/.github/template/version-branch-template.yml index 8afedfc1e6..b11bdf69b1 100644 --- a/.github/template/version-branch-template.yml +++ b/.github/template/version-branch-template.yml @@ -29,11 +29,29 @@ engine_branch: BABEL_2_4_STABLE__PG_14_7 extension_branch: BABEL_2_4_STABLE '14.8': + engine_branch: BABEL_2_5_STABLE__PG_14_8 + extension_branch: BABEL_2_5_STABLE +'14.9': + engine_branch: BABEL_2_6_STABLE__PG_14_9 + extension_branch: BABEL_2_6_STABLE +'14.10': + engine_branch: BABEL_2_7_STABLE__PG_14_10 + extension_branch: BABEL_2_7_STABLE +'14.11': engine_branch: BABEL_2_X_DEV__PG_14_X extension_branch: BABEL_2_X_DEV '15.2': engine_branch: BABEL_3_1_STABLE__PG_15_2 extension_branch: BABEL_3_1_STABLE +'15.3': + engine_branch: BABEL_3_2_STABLE__PG_15_3 + extension_branch: BABEL_3_2_STABLE +'15.4': + engine_branch: BABEL_3_3_STABLE__PG_15_4 + extension_branch: BABEL_3_3_STABLE +'15.5': + engine_branch: BABEL_3_4_STABLE__PG_15_5 + extension_branch: BABEL_3_4_STABLE 'source.latest': engine_branch: latest extension_branch: latest diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml new file mode 100644 index 0000000000..4df9a05535 --- /dev/null +++ b/.github/workflows/code-coverage.yml @@ -0,0 +1,323 @@ +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 + env: + INSTALL_DIR: psql + 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: 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: Install Extensions + id: install-extensions + if: always() && steps.build-extensions.outcome == 'success' + uses: ./.github/composite-actions/install-extensions + with: + install_dir: 'psql' + + - name: Run JDBC Tests + id: jdbc + if: always() && steps.install-extensions.outcome == 'success' + timeout-minutes: 60 + run: | + export PATH=~/${{env.INSTALL_DIR}}/bin:$PATH + export PG_SRC=~/work/babelfish_extensions/postgresql_modified_for_babelfish + cd test/JDBC/ + mvn test + + - name: Install MSSQL Tools + id: install-mssql-tools + if: always() && steps.install-extensions.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-16.00.0000.tar.gz + tar -zxvf psqlodbc-16.00.0000.tar.gz + cd psqlodbc-16.00.0000 + ./configure + sudo make + sudo make install + echo '[ODBC_Driver_16_for_PostgreSQL]' | sudo tee -a /etc/odbcinst.ini > /dev/null + echo 'Description=ODBC Driver 16 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_16_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: Drop and re-create Babelfish database + id: re-install-extensions + if: always() && steps.configure-python-environment.outcome == 'success' + run: | + sudo ~/psql/bin/psql -d postgres -U runner -v user="jdbc_user" -v db="jdbc_testdb" -f .github/scripts/cleanup_babelfish_database.sql + sudo ~/psql/bin/psql -d postgres -U runner -v user="jdbc_user" -v db="jdbc_testdb" -v migration_mode="single_db" -f .github/scripts/create_extension.sql + sqlcmd -S localhost -U "jdbc_user" -P 12345678 -Q "SELECT @@version GO" + + - name: Run Python Tests + if: always() && steps.re-install-extensions.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 diff --git a/.github/workflows/dotnet-tests.yml b/.github/workflows/dotnet-tests.yml index 3281fefcb3..5b06a9eae1 100644 --- a/.github/workflows/dotnet-tests.yml +++ b/.github/workflows/dotnet-tests.yml @@ -53,9 +53,9 @@ jobs: 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 dotnet-sdk-7.0 sudo apt-get install -y apt-transport-https - sudo apt-get install -y aspnetcore-runtime-5.0 + sudo apt-get install -y aspnetcore-runtime-7.0 - name: Run Dotnet Tests if: always() && steps.install-dotnet.outcome == 'success' diff --git a/.github/workflows/jdbc-tests-with-parallel-query.yml b/.github/workflows/jdbc-tests-with-parallel-query.yml new file mode 100644 index 0000000000..0dfb4863af --- /dev/null +++ b/.github/workflows/jdbc-tests-with-parallel-query.yml @@ -0,0 +1,95 @@ +name: JDBC Tests With Parallel Query +on: [push, pull_request] + +jobs: + run-babelfish-jdbc-tests-with-parallel-query-mode: + env: + INSTALL_DIR: psql + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + id: checkout + + - name: Install Dependencies + id: install-dependencies + if: always() + uses: ./.github/composite-actions/install-dependencies + + - name: Build Modified Postgres + id: build-modified-postgres + if: always() && steps.install-dependencies.outcome == 'success' + uses: ./.github/composite-actions/build-modified-postgres + + - name: Compile ANTLR + id: compile-antlr + if: always() && steps.build-modified-postgres.outcome == 'success' + uses: ./.github/composite-actions/compile-antlr + + - name: Build Extensions + id: build-extensions + if: always() && steps.compile-antlr.outcome == 'success' + uses: ./.github/composite-actions/build-extensions + + - name: Build tds_fdw Extension + id: build-tds_fdw-extension + if: always() && steps.build-extensions.outcome == 'success' + uses: ./.github/composite-actions/build-tds_fdw-extension + + - name: Install Extensions + id: install-extensions + if: always() && steps.build-tds_fdw-extension.outcome == 'success' + uses: ./.github/composite-actions/install-extensions + with: + parallel_query_mode: true + + - name: Run JDBC Tests + id: jdbc + if: always() && steps.install-extensions.outcome == 'success' + timeout-minutes: 120 + run: | + export PATH=~/${{env.INSTALL_DIR}}/bin:$PATH + export PG_SRC=~/work/babelfish_extensions/postgresql_modified_for_babelfish + cd test/JDBC/ + # set env variable isParallelQueryMode to true to let jdbc know not to run tests of file parallel_query_jdbc_schedule + export isParallelQueryMode=true + mvn test + # reset env variable + unset isParallelQueryMode + + - name: Cleanup babelfish database + id: cleanup + if: always() && steps.install-extensions.outcome == 'success' + run: | + sudo ~/psql/bin/psql -d postgres -U runner -v user="jdbc_user" -v db="jdbc_testdb" -f .github/scripts/cleanup_babelfish_database.sql + + - name: Upload Log + if: always() && steps.jdbc.outcome == 'failure' + uses: actions/upload-artifact@v2 + with: + name: postgres-log + path: ~/psql/data/logfile + + # The test summary files contain paths with ':' characters, which is not allowed with the upload-artifact actions + - name: Rename Test Summary Files + id: test-file-rename + if: always() && steps.jdbc.outcome == 'failure' + run: | + cd test/JDBC/Info + timestamp=`ls -Art | tail -n 1` + cd $timestamp + mv $timestamp.diff ../output-diff.diff + mv "$timestamp"_runSummary.log ../run-summary.log + + - name: Upload Run Summary + if: always() && steps.test-file-rename == 'success' + uses: actions/upload-artifact@v2 + with: + name: run-summary.log + path: test/JDBC/Info/run-summary.log + + - name: Upload Output Diff + if: always() && steps.jdbc.outcome == 'failure' + uses: actions/upload-artifact@v2 + with: + name: output-diff.diff + path: test/JDBC/Info/output-diff.diff diff --git a/.github/workflows/jdbc-tests.yml b/.github/workflows/jdbc-tests.yml index da8a9f1cb1..2c881381a7 100644 --- a/.github/workflows/jdbc-tests.yml +++ b/.github/workflows/jdbc-tests.yml @@ -3,6 +3,8 @@ on: [push, pull_request] jobs: run-babelfish-jdbc-tests: + env: + INSTALL_DIR: psql runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -43,6 +45,8 @@ jobs: if: always() && steps.install-extensions.outcome == 'success' timeout-minutes: 60 run: | + export PATH=~/${{env.INSTALL_DIR}}/bin:$PATH + export PG_SRC=~/work/babelfish_extensions/postgresql_modified_for_babelfish cd test/JDBC/ mvn test diff --git a/.github/workflows/major-version-upgrade.yml b/.github/workflows/major-version-upgrade.yml index 3aa6514a4f..5d90b5b84c 100644 --- a/.github/workflows/major-version-upgrade.yml +++ b/.github/workflows/major-version-upgrade.yml @@ -71,9 +71,17 @@ jobs: ~/${{env.OLD_INSTALL_DIR}}/bin/pg_ctl -D ~/${{env.OLD_INSTALL_DIR}}/data -l logfile13 start cd ${{env.OLD_INSTALL_DIR}}/data sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" postgresql.conf - sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds'/g" postgresql.conf + sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds, pg_stat_statements'/g" postgresql.conf ipaddress=$(ifconfig eth0 | grep 'inet ' | cut -d: -f2 | awk '{ print $2}') - sudo echo "host all all $ipaddress/32 trust" >> pg_hba.conf + # Allow only runner to have trust authentication, all other users must provide a password + { + sudo echo "local all runner trust" + sudo echo "local all all md5" + sudo echo "host all runner 127.0.0.1/32 trust" + sudo echo "host all runner $ipaddress/32 trust" + sudo echo "host all all 0.0.0.0/0 md5" + sudo echo "host all all ::/0 md5" + } > pg_hba.conf ~/${{env.OLD_INSTALL_DIR}}/bin/pg_ctl -D ~/${{env.OLD_INSTALL_DIR}}/data -l logfile13 restart cd ~/work/babelfish_extensions/babelfish_extensions/ sudo ~/${{env.OLD_INSTALL_DIR}}/bin/psql -d postgres -U runner -v user="jdbc_user" -v db="jdbc_testdb" -f .github/scripts/create_extension.sql @@ -114,9 +122,17 @@ jobs: ~/${{env.NEW_INSTALL_DIR}}/bin/initdb -D ~/${{env.NEW_INSTALL_DIR}}/data cd ~/${{env.NEW_INSTALL_DIR}}/data sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" postgresql.conf - sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds'/g" postgresql.conf + sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds, pg_stat_statements'/g" postgresql.conf ipaddress=$(ifconfig eth0 | grep 'inet ' | cut -d: -f2 | awk '{ print $2}') - sudo echo "host all all $ipaddress/32 trust" >> pg_hba.conf + # Allow only runner to have trust authentication, all other users must provide a password + { + sudo echo "local all runner trust" + sudo echo "local all all md5" + sudo echo "host all runner 127.0.0.1/32 trust" + sudo echo "host all runner $ipaddress/32 trust" + sudo echo "host all all 0.0.0.0/0 md5" + sudo echo "host all all ::/0 md5" + } > pg_hba.conf shell: bash - name: Run pg_upgrade @@ -129,6 +145,8 @@ jobs: timeout-minutes: 60 if: always() && steps.run-pg_upgrade.outcome == 'success' run: | + export PATH=~/${{env.NEW_INSTALL_DIR}}/bin:$PATH + export PG_SRC=~/work/babelfish_extensions/postgresql_modified_for_babelfish cd test/JDBC/ # temporarily ignore test BABEL-2086 echo 'ignore#!#BABEL-2086' >> jdbc_schedule diff --git a/.github/workflows/minor-version-upgrade.yml b/.github/workflows/minor-version-upgrade.yml index 67b50f895a..def7db0fc0 100644 --- a/.github/workflows/minor-version-upgrade.yml +++ b/.github/workflows/minor-version-upgrade.yml @@ -6,6 +6,7 @@ jobs: env: ENGINE_VER_FROM: BABEL_3_0_STABLE__PG_15_1 EXTENSION_VER_FROM: BABEL_3_0_STABLE + INSTALL_DIR: psql name: Build and test runs-on: ubuntu-20.04 @@ -83,6 +84,8 @@ jobs: id: jdbc timeout-minutes: 60 run: | + export PATH=~/${{env.INSTALL_DIR}}/bin:$PATH + export PG_SRC=~/work/babelfish_extensions/postgresql_modified_for_babelfish cd test/JDBC/ mvn test diff --git a/.github/workflows/odbc-tests.yml b/.github/workflows/odbc-tests.yml index 99f5659c56..bd8572c6fd 100644 --- a/.github/workflows/odbc-tests.yml +++ b/.github/workflows/odbc-tests.yml @@ -58,14 +58,14 @@ jobs: if: 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 + wget https://ftp.postgresql.org/pub/odbc/versions/src/psqlodbc-16.00.0000.tar.gz + tar -zxvf psqlodbc-16.00.0000.tar.gz + cd psqlodbc-16.00.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 '[ODBC_Driver_16_for_PostgreSQL]' | sudo tee -a /etc/odbcinst.ini > /dev/null + echo 'Description=ODBC Driver 16 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 @@ -81,7 +81,7 @@ jobs: 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_ODBC_DRIVER_NAME=ODBC_Driver_16_for_PostgreSQL \ PSQL_BABEL_DB_SERVER=localhost \ PSQL_BABEL_DB_PORT=5432 \ PSQL_BABEL_DB_USER=jdbc_user \ diff --git a/.github/workflows/pg_dump-restore-test.yml b/.github/workflows/pg_dump-restore-test.yml index 6e9550f349..071267b540 100644 --- a/.github/workflows/pg_dump-restore-test.yml +++ b/.github/workflows/pg_dump-restore-test.yml @@ -15,7 +15,13 @@ 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[itm.length - 1]['logical-database'] + ')') + itm.map(i => i.version.toString().replace(/[.]/g, \"_\")).join(\"-\"), \ + last_version: itm[itm.length - 1].version.toString().replace(/[.]/g, \"_\"), \ + dump_method: itm[itm.length - 1]['dump-data-as'] == 'copy' ? 'COPY' : 'INSERTS', \ + dump_format: itm[itm.length - 1]['dump-format']})); \ + console.log(JSON.stringify(p));") echo "::set-output name=dump-restore-path-list::$DUMP_RESTORE_PATH_LIST" run-dump-restore-test: @@ -24,7 +30,7 @@ jobs: fail-fast: false matrix: upgrade-path: ${{ fromJson(needs.generate-dump-restore-tests.outputs.dump-restore-path-list) }} - name: Run Dump Restore Test for ${{ matrix.upgrade-path.title }} + name: Dump Restore Test using ${{ matrix.upgrade-path.dump_method }} for ${{ matrix.upgrade-path.title }} - format=${{ matrix.upgrade-path.dump_format }} runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 @@ -43,6 +49,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 +75,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 @@ -125,7 +135,7 @@ jobs: if: always() && (steps.setup-base-version.outcome == 'failure' || steps.dump-restore-and-test.outcome == 'failure') uses: actions/upload-artifact@v2 with: - name: upgrade-logs-${{ matrix.upgrade-path.title }} + name: upgrade-logs-${{ matrix.upgrade-path.dump_method }}-${{ matrix.upgrade-path.title }}-${{ matrix.upgrade-path.dump_format }} path: | ~/upgrade/* ~/psql*/data/logfile 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/.github/workflows/tap-tests.yml b/.github/workflows/tap-tests.yml index fe8f86fb94..32fd64d8b7 100644 --- a/.github/workflows/tap-tests.yml +++ b/.github/workflows/tap-tests.yml @@ -4,7 +4,10 @@ on: [push, pull_request] jobs: run-babelfish-tap-tests: env: - INSTALL_DIR: psql + OLD_INSTALL_DIR: psql_source + NEW_INSTALL_DIR: psql_target + ENGINE_BRANCH_OLD: BABEL_2_6_STABLE__PG_14_9 + EXTENSION_BRANCH_OLD: BABEL_2_6_STABLE runs-on: ubuntu-20.04 steps: @@ -33,37 +36,64 @@ jobs: sudo -E apt-get install krb5-admin-server krb5-kdc krb5-user libkrb5-dev -y -qq shell: bash - - name: Build Modified Postgres - id: build-modified-postgres + - name: Build Modified Postgres using ${{env.ENGINE_BRANCH_OLD}} + id: build-modified-postgres-old if: always() && steps.install-kerberos-dependencies.outcome == 'success' - with: - tap_tests: 'yes' uses: ./.github/composite-actions/build-modified-postgres + with: + engine_branch: ${{env.ENGINE_BRANCH_OLD}} + install_dir: ${{env.OLD_INSTALL_DIR}} - name: Compile ANTLR id: compile-antlr - if: always() && steps.build-modified-postgres.outcome == 'success' + if: always() && steps.build-modified-postgres-old.outcome == 'success' uses: ./.github/composite-actions/compile-antlr + with: + install_dir: ${{env.OLD_INSTALL_DIR}} - - name: Build Extensions - id: build-extensions + - name: Build Extensions using ${{env.EXTENSION_BRANCH_OLD}} + id: build-extensions-old if: always() && steps.compile-antlr.outcome == 'success' uses: ./.github/composite-actions/build-extensions + with: + install_dir: ${{env.OLD_INSTALL_DIR}} + extension_branch: ${{env.EXTENSION_BRANCH_OLD}} + + - uses: actions/checkout@v2 + + - name: Build Modified Postgres using latest version + id: build-modified-postgres-new + if: always() && steps.build-extensions-old.outcome == 'success' + uses: ./.github/composite-actions/build-modified-postgres + with: + tap_tests: 'yes' + install_dir: ${{env.NEW_INSTALL_DIR}} + + - name: Copy ANTLR + run: cp "/usr/local/lib/libantlr4-runtime.so.4.9.3" ~/${{env.NEW_INSTALL_DIR}}/lib/ + + - name: Build Extensions using latest version + id: build-extensions-new + if: always() && steps.build-modified-postgres-new.outcome == 'success' + uses: ./.github/composite-actions/build-extensions + with: + install_dir: ${{env.NEW_INSTALL_DIR}} - name: Run TAP Tests id: tap - if: always() && steps.build-extensions.outcome == 'success' + if: always() && steps.build-extensions-new.outcome == 'success' timeout-minutes: 5 run: | - export PG_CONFIG=~/${{env.INSTALL_DIR}}/bin/pg_config + export PG_CONFIG=~/${{env.NEW_INSTALL_DIR}}/bin/pg_config export PATH=/opt/mssql-tools/bin:$PATH + export oldinstall=$HOME/${{env.OLD_INSTALL_DIR}} cd contrib/babelfishpg_tds - make installcheck PROVE_TESTS="t/001_tdspasswd.pl t/002_tdskerberos.pl t/003_bbfextnotloaded.pl" + make installcheck PROVE_TESTS="t/001_tdspasswd.pl t/002_tdskerberos.pl t/003_bbfextnotloaded.pl t/004_bbfdumprestore.pl" - name: Upload Logs if: always() && steps.tap.outcome == 'failure' uses: actions/upload-artifact@v2 with: name: tap_tests_logs - path: contrib/babelfishpg_tds/test/tmp_check/log + path: contrib/babelfishpg_tds/test/tmp_check diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000000..f59bc93901 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,61 @@ +name: Unit Tests +on: [push, pull_request] + +jobs: + run-babelfish-unit-tests: + env: + INSTALL_DIR: psql + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + id: checkout + + - name: Install Dependencies + id: install-dependencies + if: always() + uses: ./.github/composite-actions/install-dependencies + + - name: Build Modified Postgres + id: build-modified-postgres + if: always() && steps.install-dependencies.outcome == 'success' + uses: ./.github/composite-actions/build-modified-postgres + + - name: Compile ANTLR + id: compile-antlr + if: always() && steps.build-modified-postgres.outcome == 'success' + uses: ./.github/composite-actions/compile-antlr + + - name: Build Extensions + id: build-extensions + if: always() && steps.compile-antlr.outcome == 'success' + uses: ./.github/composite-actions/build-extensions + + - name: Install Extensions + id: install-extensions + if: always() && steps.build-extensions.outcome == 'success' + uses: ./.github/composite-actions/install-extensions + + - name: Build babelfishpg_unit + id: build-babelfishpg_unit + if: always() && steps.install-extensions.outcome == 'success' + uses: ./.github/composite-actions/build-babelfishpg_unit + + - name: Run Unit Tests + id: unit + if: always() && steps.build-babelfishpg_unit.outcome == 'success' + timeout-minutes: 60 + run: | + sudo ~/psql/bin/psql -d jdbc_testdb -U runner -f .github/scripts/unit_tests.sql > >(tee ~/psql/output.out) + count=$(awk -F '|' '$2 ~ /fail/' ~/psql/output.out | wc -l) + if [ "$count" -gt 0 ]; then + echo "Tests failed: $count" + exit 1 + fi + rm -rf ~/psql/output.out + + - name: Upload Log + if: always() && steps.unit.outcome == 'failure' + uses: actions/upload-artifact@v2 + with: + name: postgres-log + path: ~/psql/data/logfile diff --git a/.gitignore b/.gitignore index a63fab7a39..e2b9f4e9c6 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/* @@ -30,6 +37,8 @@ contrib/babelfishpg_tsql/src/backend_parser/gram-backend.y contrib/babelfishpg_tsql/src/backend_parser/kwlist_d.h contrib/babelfishpg_tsql/src/backend_parser/scan-backend.c contrib/babelfishpg_tsql/src/backend_parser/scan-backend.l +contrib/babelfishpg_tsql/src/fts_parser.c +contrib/babelfishpg_tsql/src/fts_scan.c contrib/babelfishpg_tsql/src/pl_gram.c contrib/babelfishpg_tsql/src/pl_gram.h contrib/babelfishpg_tsql/src/pl_gram.output \ No newline at end of file diff --git a/INSTALLING.md.tmpl b/INSTALLING.md.tmpl new file mode 100644 index 0000000000..0659c528df --- /dev/null +++ b/INSTALLING.md.tmpl @@ -0,0 +1,345 @@ +# Compiling Babelfish from distribution tarballs + +This document will walk you through the steps required to create a working Babelfish installation on an Ubuntu 20.04 Linux host. Please note that the steps may vary on other operating systems, but the overall process is roughly the same. + +The installation steps that follow are for the release tar or zip file, which uses content from the following repositories: + +- the [PostgreSQL database engine source code repository](https://github.com/babelfish-for-postgresql/postgresql_modified_for_babelfish), with changes that provide the protocols, language parsers, and features required by Babelfish. +- the [extensions repository](https://github.com/babelfish-for-postgresql/babelfish_extensions) - extensions support the T-SQL protocol, the T-SQL language, the TDS Protocol, and other Babelfish behaviors. + +## Prerequisites + +### Hardware and Specs + +The current installation instructions were tested using `t4g.large`, `t4.large`, and `c6g.xlarge` instances as hosts. + +This installation has also been tested on [ami-0fb653ca2d3203ac1 for amd64](https://us-east-2.console.aws.amazon.com/ec2/v2/home?region=us-east-2#Images:visibility=public-images;imageId=ami-0fb653ca2d3203ac1), and [ami-02af65b2d1ebdfafc for arm64](https://us-east-2.console.aws.amazon.com/ec2/v2/home?region=us-east-2#Images:visibility=public-images;imageId=ami-02af65b2d1ebdfafc). + +To compile Babelfish, you should have at least 4GB of available memory. + +### Required Software + +Install the following dependencies: + +``` +sudo apt-get update && sudo apt install -y --no-install-recommends \ + build-essential flex libxml2-dev libxml2-utils \ + libxslt-dev libssl-dev libreadline-dev zlib1g-dev \ + libldap2-dev libpam0g-dev gettext uuid uuid-dev \ + cmake lld apt-utils libossp-uuid-dev gnulib bison \ + xsltproc icu-devtools libicu66 \ + libicu-dev gawk \ + curl openjdk-8-jre openssl \ + g++ libssl-dev python-dev libpq-dev \ + pkg-config libutfcpp-dev \ + gnupg unixodbc-dev net-tools unzip +``` + +If you would like to work with Kerberos authentication then additional dependency is required on `libkrb5-dev` package. + +Many of the Babelfish prerequisites are part of a typical Linux distribution. You may find that the packages on your distribution use a similar (but not identical) name. + +To build Babelfish, you will need access to a user with root privileges, so you can convey privileges with `sudo`. You'll also need a non-root user to initialize the database; PostgreSQL does not allow a root user to own the `data` directory or start the server. + + +### Set environment variables + +Navigate into the extracted distribution folder and set the following environment variables: + +```sh +export JOBS=4 # Adjust to number of cores +export BABELFISH_HOME=/opt/babelfish/{{VERSION}} +export PG_CONFIG=${BABELFISH_HOME}/bin/pg_config +export PG_SRC=$(realpath $PWD) +``` + +### Compile ANTLR 4 + +Unfortunately, there are [no prebuilt C++ binaries for the Antlr 4.9.3 runtime version](https://www.antlr.org/download.html) for Linux. You will need to compile and install ANTLR manually. + +First, define the following variables in your environment: + +```sh +export ANTLR4_VERSION=4.9.3 +export ANTLR4_JAVA_BIN=/usr/bin/java +export ANTLR4_RUNTIME_LIBRARIES=/usr/include/antlr4-runtime +export ANTLR_EXECUTABLE=/usr/local/lib/antlr-${ANTLR4_VERSION}-complete.jar +export ANTLR_RUNTIME=~/antlr4 +``` + +The [Antlr 4.9.3 Runtime](https://www.antlr.org/) files are distributed with the Babelfish source code. Use the following commands to copy the files into place: + +```sh +sudo cp ${PG_SRC}/contrib/babelfishpg_tsql/antlr/thirdparty/antlr/antlr-${ANTLR4_VERSION}-complete.jar /usr/local/lib +``` + +After copying the ANTLR .jar files into place, compile ANTLR: + +```sh +cd ${HOME} + +wget http://www.antlr.org/download/antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip +unzip -d ${ANTLR_RUNTIME} antlr4-cpp-runtime-${ANTLR4_VERSION}-source.zip + +cd ${ANTLR_RUNTIME} +mkdir build && cd build +cmake .. -D ANTLR_JAR_LOCATION=/usr/local/lib/antlr-${ANTLR4_VERSION}-complete.jar -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_DEMO=True +make -j $JOBS +sudo make install +``` + +## Build modified PostgreSQL for Babelfish + +The version of PostgreSQL that is distributed with Babelfish includes hooks that allow Babelfish to implement behaviors. Babelfish will not work with PostgreSQL distributions from other sources. Use the following commands to configure the build environment and build the Babelfish PostgreSQL distribution: + +```sh +cd ${PG_SRC} + +./configure CFLAGS="-ggdb" \ + --prefix=${BABELFISH_HOME}/ \ + --enable-debug \ + --with-ldap \ + --with-libxml \ + --with-pam \ + --with-uuid=ossp \ + --enable-nls \ + --with-libxslt \ + --with-icu + +make DESTDIR=${BABELFISH_HOME}/ -j $JOBS 2>error.txt + +sudo make install +``` +> NOTE: To build Babelfish with Kerberos authentication support, use the option `--with-gssapi` during configuration. + +> WARNING: Using the --with-extra-version option during the configuration phase can break the sys.get_host_os() output; we do not recommend including it. + +Build and install the extensions because `uuid-ossp.so` is a runtime dependency for Babelfish: + +```sh +cd ${PG_SRC}/contrib && make -j ${JOBS} && sudo make install +``` + +### Compile the ANTLR parser generator + +Use the following commands to compile the ANTLR parser generator and copy the runtime to the PostgreSQL library location: + +``` sh +export cmake=$(which cmake) + +sudo cp /usr/local/lib/libantlr4-runtime.so.${ANTLR4_VERSION} ${BABELFISH_HOME}/lib + +cd ${PG_SRC}/contrib/babelfishpg_tsql/antlr +cmake -Wno-dev . +make all +``` + +### Compile the contrib modules and build Babelfish + +Now, it is time to compile the contrib modules and build Babelfish. Use the command: + +```sh +cd ${PG_SRC}/contrib +for ext in babelfishpg_common babelfishpg_money babelfishpg_tds babelfishpg_tsql +do + cd $ext + make -j ${JOBS} + sudo make PG_CONFIG=${PG_CONFIG} install + cd .. +done +``` + +## Setting up the PostgreSQL modified instance + +The steps required to create a new cluster and start the service are very similar to the steps required by a community PostgreSQL installation: + +```sh +sudo mkdir -p /var/lib/babelfish/{{VERSION}} + +sudo adduser postgres --home /var/lib/babelfish +``` + +Ensure that the related folders hold the permissions for the service user: + +```sh +sudo chown -R postgres: /opt/babelfish/ +sudo chown -R postgres: /var/lib/babelfish/ +``` + +Switch to the `postgres` user (a non-superuser) and start the cluster: + +```sh +sudo su - postgres +export BABELFISH_HOME=/opt/babelfish/{{VERSION}} +export BABELFISH_DATA=/var/lib/babelfish/{{VERSION}}/data +``` + +### Initializing the Data directory + +#### Initialize data with trustable connection for development + +If you would like to create a local cluster for testing purposes, you can configure trust authentication when initializing the database to simplify authentication. The `--auth-host=trust` flag will create the cluster using trust authentication, and should not be included if you are creating an instance that will contain sensitive information: + +```sh +${BABELFISH_HOME}/bin/initdb -D ${BABELFISH_DATA}/ -E "UTF8" --auth=trust --auth-host=trust --auth-local=trust +``` + +#### Initialize data with specific HBA configuration + +For production or isolated environments, it is recommended to specify the allowed IP addresses that can access the system and a secure authentication method such as `md5` in the `pg_hba.conf`. For other supported methods see [Authentication Methods documentation](https://www.postgresql.org/docs/15/auth-methods.html). + +```sh +${BABELFISH_HOME}/bin/initdb -D ${BABELFISH_DATA}/ -E "UTF8" +``` + +Once the data directory is initialized, edit the `${BABELFISH_DATA}/pg_hba.conf` file following the [vanilla Postgres HBA configuration](https://www.postgresql.org/docs/15/auth-pg-hba-conf.html). + + + +### Configuring PostgreSQL for Babelfish + +The `postgresql.conf` configuration changes shown below are required before starting the service: + +```sh +cat << EOF >> ${BABELFISH_DATA}/postgresql.conf + +#------------------------------------------------------------------------------ +# BABELFISH RELATED OPTIONS +# These are going to step over previous duplicated variables. +#------------------------------------------------------------------------------ +listen_addresses = '*' +allow_system_table_mods = on +shared_preload_libraries = 'babelfishpg_tds' +babelfishpg_tds.listen_addresses = '*' +EOF + +``` + +> For more information about Babelfish variables, see [Configuring Babelfish](https://babelfishpg.org/docs/internals/configuration/) + +Then, start the instance with the following command: + +```sh +${BABELFISH_HOME}/bin/pg_ctl -D ${BABELFISH_DATA}/ -l logfile start +``` + +### Enabling extensions in the target database + +Create a user (babelfish_user) and the database (babelfish_db) into which the extensions will be installed: + +```sh +${BABELFISH_HOME}/bin/psql -d postgres -U postgres -c "CREATE USER babelfish_user WITH SUPERUSER CREATEDB CREATEROLE PASSWORD '12345678' INHERIT;" +${BABELFISH_HOME}/bin/psql -d postgres -U postgres -c "DROP DATABASE IF EXISTS babelfish_db;" +${BABELFISH_HOME}/bin/psql -d postgres -U postgres -c "CREATE DATABASE babelfish_db OWNER babelfish_user;" +``` + +Connect to the babelfish_db database, and configure and install the extensions: + +```sh +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "CREATE EXTENSION IF NOT EXISTS "babelfishpg_tds" CASCADE;" +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "GRANT ALL ON SCHEMA sys to babelfish_user;" +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "ALTER USER babelfish_user CREATEDB;" +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "ALTER SYSTEM SET babelfishpg_tsql.database_name = 'babelfish_db';" +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "SELECT pg_reload_conf();" +``` + + +By default, the `migration_mode` is `single-db`. To deploy in `multi-db` mode, you need to modify the Babelfish configuration file before initializing the database: + +```sh +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "ALTER DATABASE babelfish_db SET babelfishpg_tsql.migration_mode = 'multi-db';" +``` + +> For more information about the `migration_mode`, see [Single vs. multiple instances](https://babelfishpg.org/docs/installation/single-multiple/) and [Choosing a migration mode](https://babelfishpg.org/docs/installation/single-multiple/#choosing-a-migration-mode). + + +Finally, initialize the database by calling _sys.initialize_babelfish_: + +```sh +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "CALL sys.initialize_babelfish('babelfish_user');" +``` + +## Connecting to the Babelfish Database through TDS port + +For testing, we're going to use FreeTDS command-line client, available for both _x86_ and _arm64_ platforms: + +- Exit postgres user: + +```sh +exit +``` + +- Install the packages: + +```sh +sudo apt install -y freetds-bin freetds-common +``` + +- Connect with `tsql`: + +```sh +$ tsql -H localhost -U babelfish_user -p 1433 -P 12345678 -D master +locale is "C.UTF-8" +locale charset is "UTF-8" +using default charset "UTF-8" +Setting master as default database in login packet +Changed database context to 'master'. +1> SELECT @@VERSION +2> GO +version +Babelfish for PostgreSQL with SQL Server Compatibility - 12.0.2000.8 +... +Copyright (c) Amazon Web Services +PostgreSQL {{ENGINE}} Babelfish for PostgreSQL on x86_64-pc-linux-gnu +(1 row affected) +``` + +If you are testing from a remote server, add the `-H` option: + +```sh +tsql -H localhost -U babelfish_user -p 1433 -P 12345678 -D master -H ${ip_address} +``` + +- If you're a sqlcmd user, the following command will access the database with a `sqlcmd` client: + +```sh +sqlcmd -S localhost -U babelfish_user -P 12345678 +``` + +> Note that `mssql-tools` does not support _arm64_ packages. + +## How to build and install the babelfishpg_unit extension and run unit tests (Optional) + +Build the babelfishpg_unit module. Use the command: + +``` +cd ${PG_SRC}/contrib/babelfishpg_unit +make -j ${JOBS} +sudo make PG_CONFIG=${PG_CONFIG} install +``` + +After babelfishpg_unit is built successfully, connect through psql endpoint and install the extension: + +``` +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "CREATE EXTENSION IF NOT EXISTS "babelfishpg_unit";" +``` + +To run unit tests: +``` +${BABELFISH_HOME}/bin/psql -d babelfish_db -U postgres -c "SELECT * FROM babelfishpg_unit.babelfishpg_unit_run_tests();" +``` + +## How to build the babelfishpg_tsql extension with linked servers enabled + +- 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). The linked servers feature is supported using the FreeTDS library which is licensed under the GNU LGPL license. See [COPYING_LIB.txt](https://github.com/FreeTDS/freetds/blob/master/COPYING_LIB.txt) for details. +- 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 +``` +- Create rest of the Babelfish extensions as usual, and initialize Babelfish. +- Create the `tds_fdw` extension in the Babelfish database: +``` +babelfish_db=> CREATE EXTENSION tds_fdw; +CREATE EXTENSION +``` diff --git a/README.md b/README.md index be76e7e675..522994f504 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ extensions that comprise Babelfish. Note that these extensions depend on patches to community PostgreSQL. A repository of those modifications can be found [here](https://github.com/babelfish-for-postgresql/postgresql_modified_for_babelfish). -Build instructions can be found [here](https://github.com/babelfish-for-postgresql/babelfish_extensions/blob/BABEL_1_X_DEV/contrib/README.md). +Build instructions can be found [here](contrib/README.md). More information about Babelfish can be found at [babelfishpg.org](https://babelfishpg.org). diff --git a/contrib/README.md b/contrib/README.md index caf83253e6..34096b084b 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -1,6 +1,6 @@ # Contents -This package includes 4 extensions: +This package includes 5 extensions: - babelfishpg_tsql @@ -11,6 +11,8 @@ This package includes 4 extensions: - Supports the various datatypes in MSSQL. - babelfishpg_money - supports the `money` type in MSSQL. This is a variation of the opensource fixeddecimal extension. +- babelfishpg_unit + - Unit testing framework for babelfish. # How do I build the extensions? @@ -43,6 +45,11 @@ The following build instructions comply with Ubuntu 20.04 and Amazon Linux 2 env make -j 4 2>error.txt make install make check + ``` + + Alternatively, if you want to build the engine with SSL support, configure the PG engine with `--with-openssl`: + ``` + ./configure --prefix=$HOME/postgres/ --without-readline --without-zlib --enable-debug --enable-cassert CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu --with-openssl ``` Also build and install the extensions because uuid-ossp.so is a runtime dependency for babelfish: @@ -146,6 +153,11 @@ The following build instructions comply with Ubuntu 20.04 and Amazon Linux 2 env cd ../babelfishpg_tsql make && make install +Build babelfishpg_unit extension if you want to run/add unit tests (Optional): + + cd contrib/babelfishpg_unit + make && make install + # How to install the extensions and how to connect via SQLCMD? @@ -183,7 +195,27 @@ The following build instructions comply with Ubuntu 20.04 and Amazon Linux 2 env ~/postgres/bin/pg_ctl -D ~/postgres/data/ -l logfile restart ``` -4. Connect via psql using the command `~/postgres/bin/psql -U your_user_name`. Create the extension and set up essential parameters. Please be aware you need to choose either 'single-db' or 'multi-db' mode during this provisioning step and you CAN NOT change it later. Refer to our documentation page for more information on 'single-db' vs 'multi-db' mode. +4. Additionally, if you want to configure the babelfish server with SSL enabled: +- Create private key and certificate as mentioned [here](https://www.postgresql.org/docs/current/ssl-tcp.html#SSL-CERTIFICATE-CREATION). + +- Modify `~/postgres/data/postgresql.conf` by uncommenting and adjusting the following 3 properties as mentioned [here](https://www.postgresql.org/docs/current/ssl-tcp.html#SSL-SERVER-FILES): + ``` + ssl = on + ssl_cert_file = 'server.crt' + ssl_key_file = 'server.key' + ``` + +- Modify `~/postgres/data/pg_hba.conf` to allow SSL connections from allowed IP addresses, replacing 10.x.y.z with your IP address. E.g. + ``` + hostssl all all 10.x.y.z/32 trust + ``` + +- Now run this to apply the changes: + ``` + ~/postgres/bin/pg_ctl -D ~/postgres/data/ -l logfile restart + ``` + +5. Connect via psql using the command `~/postgres/bin/psql -U your_user_name`. Create the extension and set up essential parameters. Please be aware you need to choose either 'single-db' or 'multi-db' mode during this provisioning step and you CAN NOT change it later. Refer to our documentation page for more information on 'single-db' vs 'multi-db' mode. ``` CREATE USER babelfish_user WITH CREATEDB CREATEROLE PASSWORD '12345678' INHERIT; DROP DATABASE IF EXISTS babelfish_db; @@ -201,11 +233,40 @@ The following build instructions comply with Ubuntu 20.04 and Amazon Linux 2 env ``` sudo ~/postgres/bin/psql -d postgres -U your_user_name ``` + - If you want to install babelfishpg_unit extension, run the following command after connecting from psql endpoint (switch to the database where babelfish extensions are installed): + ``` + \c babelfish_db + CREATE EXTENSION IF NOT EXISTS "babelfishpg_unit"; + ``` -5. Try connecting to Babelfish via SQLCMD +6. Try connecting to Babelfish via SQLCMD ``` sqlcmd -S localhost -U babelfish_user -P 12345678 ``` + Alternatively, use the -N and -C flags to request encryption and trust the server certificate respectively: + ``` + sqlcmd -N -C -S localhost -U babelfish_user -P 12345678 + ``` +7. You can query the pg_stat_ssl view to see if the connection is encrypted using SSL: + ``` + 1> select * from pg_stat_ssl where pid = @@spid + 2> go + pid ssl version cipher bits client_dn client_serial issuer_dn + ----------- --- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 8426 1 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256 NULL NULL NULL + + + (1 rows affected) + ``` + + +# How to run the unit tests? +Run the following command from psql endpoint using `~/postgres/bin/psql -U your_user_name -d babelfish_db`: + +``` +SELECT * FROM babelfishpg_unit.babelfishpg_unit_run_tests(); +``` + # How to run the JDBC regression tests? 1. Install Maven: https://maven.apache.org/install.html 2. cd to test/JDBC @@ -219,3 +280,27 @@ 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). The linked servers feature is supported using the FreeTDS library which is licensed under the GNU LGPL license. See [COPYING_LIB.txt](https://github.com/FreeTDS/freetds/blob/master/COPYING_LIB.txt) for details. +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 + ``` + + +# How to build the Babelfish server with Kerberos authentication enabled + +Please note that Kerberos authentication feature is available on Babelfish server with version 3.1.0 or higher. + +1. To build the Babelfish server with Kerberos authentication enabled, you will need to install `build-essential` and `libkrb5-dev` packages. +2. Build the Babelfish server according to the instructions mentioned [here](https://github.com/babelfish-for-postgresql/babelfish_extensions/blob/BABEL_3_X_DEV/contrib/README.md#build-the-postgres-engine) and use --with-gssapi flag to configure Babelfish in order to enable the GSSAPI APIs. diff --git a/contrib/babelfishpg_common/Makefile b/contrib/babelfishpg_common/Makefile index 1f91a4420c..6a5666f691 100644 --- a/contrib/babelfishpg_common/Makefile +++ b/contrib/babelfishpg_common/Makefile @@ -12,7 +12,7 @@ PREV_EXTVERSION = 1.0.0 MODULEPATH = $$libdir/$(EXTENSION)-$(BBFPGCMN_MAJOR_VERSION) MODULE_big = $(EXTENSION) -PG_CFLAGS += -g -Werror +PG_CFLAGS += -g -Werror -Wfloat-conversion PG_CFLAGS += -fstack-protector-strong ifdef PREV_EXTVERSION DATA = sql/$(EXTENSION)--$(PREV_EXTVERSION).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/binary.sql b/contrib/babelfishpg_common/sql/binary.sql index 58f9037dfb..98e0b425e4 100644 --- a/contrib/babelfishpg_common/sql/binary.sql +++ b/contrib/babelfishpg_common/sql/binary.sql @@ -46,6 +46,12 @@ CREATE TYPE sys.BBF_BINARY ( COLLATABLE = false ); +CREATE CAST (sys.BBF_BINARY AS sys.BBF_VARBINARY) +WITHOUT FUNCTION AS IMPLICIT; + +CREATE CAST (sys.BBF_VARBINARY AS sys.BBF_BINARY) +WITHOUT FUNCTION AS IMPLICIT; + -- casting functions for sys.BINARY CREATE OR REPLACE FUNCTION sys.varcharbinary(sys.VARCHAR, integer, boolean) RETURNS sys.BBF_BINARY 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/bpchar.sql b/contrib/babelfishpg_common/sql/bpchar.sql index e8c3226004..8398a7fca8 100644 --- a/contrib/babelfishpg_common/sql/bpchar.sql +++ b/contrib/babelfishpg_common/sql/bpchar.sql @@ -294,6 +294,7 @@ CREATE OR REPLACE AGGREGATE sys.max(sys.BPCHAR) sfunc = sys.bpchar_larger, stype = sys.bpchar, combinefunc = sys.bpchar_larger, + sortop = >, parallel = safe ); @@ -302,6 +303,7 @@ CREATE OR REPLACE AGGREGATE sys.min(sys.BPCHAR) sfunc = sys.bpchar_smaller, stype = sys.bpchar, combinefunc = sys.bpchar_smaller, + sortop = <, parallel = safe ); diff --git a/contrib/babelfishpg_common/sql/datetime.sql b/contrib/babelfishpg_common/sql/datetime.sql index b8a74bf6e4..99598da055 100644 --- a/contrib/babelfishpg_common/sql/datetime.sql +++ b/contrib/babelfishpg_common/sql/datetime.sql @@ -152,6 +152,7 @@ CREATE OR REPLACE AGGREGATE sys.max(sys.DATETIME) sfunc = sys.datetime_larger, stype = sys.datetime, combinefunc = sys.datetime_larger, + sortop = >, parallel = safe ); @@ -160,6 +161,7 @@ CREATE OR REPLACE AGGREGATE sys.min(sys.DATETIME) sfunc = sys.datetime_smaller, stype = sys.datetime, combinefunc = sys.datetime_smaller, + sortop = <, parallel = safe ); @@ -530,3 +532,38 @@ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; CREATE CAST (FIXEDDECIMAL AS sys.DATETIME) WITH FUNCTION sys.money2datetime (FIXEDDECIMAL) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.datetime_to_bit(IN arg sys.DATETIME) +RETURNS SYS.BIT +AS 'babelfishpg_common', 'datetime_to_bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_int2(IN arg sys.DATETIME) +RETURNS INT2 +AS 'babelfishpg_common', 'datetime_to_int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_int4(IN arg sys.DATETIME) +RETURNS INT4 +AS 'babelfishpg_common', 'datetime_to_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_int8(IN arg sys.DATETIME) +RETURNS INT8 +AS 'babelfishpg_common', 'datetime_to_int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_float4(IN arg sys.DATETIME) +RETURNS float4 +AS 'babelfishpg_common', 'datetime_to_float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_float8(IN arg sys.DATETIME) +RETURNS float8 +AS 'babelfishpg_common', 'datetime_to_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_numeric(IN arg sys.DATETIME) +RETURNS NUMERIC +AS 'babelfishpg_common', 'datetime_to_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/babelfishpg_common/sql/datetime2.sql b/contrib/babelfishpg_common/sql/datetime2.sql index 01e554d0b7..a007f09ee4 100644 --- a/contrib/babelfishpg_common/sql/datetime2.sql +++ b/contrib/babelfishpg_common/sql/datetime2.sql @@ -176,6 +176,7 @@ CREATE OR REPLACE AGGREGATE sys.max(sys.DATETIME2) sfunc = sys.datetime2_larger, stype = sys.datetime2, combinefunc = sys.datetime2_larger, + sortop = >, parallel = safe ); @@ -184,6 +185,7 @@ CREATE OR REPLACE AGGREGATE sys.min(sys.DATETIME2) sfunc = sys.datetime2_smaller, stype = sys.datetime2, combinefunc = sys.datetime2_smaller, + sortop = <, parallel = safe ); diff --git a/contrib/babelfishpg_common/sql/datetimeoffset.sql b/contrib/babelfishpg_common/sql/datetimeoffset.sql index 616b1b53c1..213916480c 100644 --- a/contrib/babelfishpg_common/sql/datetimeoffset.sql +++ b/contrib/babelfishpg_common/sql/datetimeoffset.sql @@ -218,6 +218,7 @@ CREATE OR REPLACE AGGREGATE sys.max(sys.DATETIMEOFFSET) sfunc = sys.datetimeoffset_larger, stype = sys.datetimeoffset, combinefunc = sys.datetimeoffset_larger, + sortop = >, parallel = safe ); @@ -226,6 +227,7 @@ CREATE OR REPLACE AGGREGATE sys.min(sys.DATETIMEOFFSET) sfunc = sys.datetimeoffset_smaller, stype = sys.datetimeoffset, combinefunc = sys.datetimeoffset_smaller, + sortop = <, parallel = safe ); diff --git a/contrib/babelfishpg_common/sql/smalldatetime.sql b/contrib/babelfishpg_common/sql/smalldatetime.sql index 4bb8521b7f..5143f46aa0 100644 --- a/contrib/babelfishpg_common/sql/smalldatetime.sql +++ b/contrib/babelfishpg_common/sql/smalldatetime.sql @@ -152,6 +152,7 @@ CREATE OR REPLACE AGGREGATE sys.max(sys.SMALLDATETIME) sfunc = sys.smalldatetime_larger, stype = sys.smalldatetime, combinefunc = sys.smalldatetime_larger, + sortop = >, parallel = safe ); @@ -160,6 +161,7 @@ CREATE OR REPLACE AGGREGATE sys.min(sys.SMALLDATETIME) sfunc = sys.smalldatetime_smaller, stype = sys.smalldatetime, combinefunc = sys.smalldatetime_smaller, + sortop = <, parallel = safe ); @@ -727,4 +729,39 @@ $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; CREATE CAST (FIXEDDECIMAL AS sys.SMALLDATETIME) -WITH FUNCTION sys.money2smalldatetime (FIXEDDECIMAL) AS IMPLICIT; \ No newline at end of file +WITH FUNCTION sys.money2smalldatetime (FIXEDDECIMAL) AS IMPLICIT; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_bit(IN arg sys.SMALLDATETIME) +RETURNS SYS.BIT +AS 'babelfishpg_common', 'smalldatetime_to_bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_int2(IN arg sys.SMALLDATETIME) +RETURNS INT2 +AS 'babelfishpg_common', 'smalldatetime_to_int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_int4(IN arg sys.SMALLDATETIME) +RETURNS INT4 +AS 'babelfishpg_common', 'smalldatetime_to_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_int8(IN arg sys.SMALLDATETIME) +RETURNS INT8 +AS 'babelfishpg_common', 'smalldatetime_to_int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_float4(IN arg sys.SMALLDATETIME) +RETURNS float4 +AS 'babelfishpg_common', 'smalldatetime_to_float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_float8(IN arg sys.SMALLDATETIME) +RETURNS float8 +AS 'babelfishpg_common', 'smalldatetime_to_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_numeric(IN arg sys.SMALLDATETIME) +RETURNS NUMERIC +AS 'babelfishpg_common', 'smalldatetime_to_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/babelfishpg_common/sql/string_operators.sql b/contrib/babelfishpg_common/sql/string_operators.sql index 6eed4a593a..811a84a020 100644 --- a/contrib/babelfishpg_common/sql/string_operators.sql +++ b/contrib/babelfishpg_common/sql/string_operators.sql @@ -1,19 +1,9 @@ -- Wrap built-in CONCAT function to accept two text arguments. -- This is necessary because CONCAT accepts arguments of type VARIADIC "any". -- CONCAT also automatically handles NULL which || does not. -CREATE OR REPLACE FUNCTION sys.babelfish_concat_wrapper(leftarg text, rightarg text) RETURNS TEXT AS -$$ - SELECT - CASE WHEN (current_setting('babelfishpg_tsql.concat_null_yields_null') = 'on') THEN - CASE - WHEN leftarg IS NULL OR rightarg IS NULL THEN NULL - ELSE CONCAT(leftarg, rightarg) - END - ELSE - CONCAT(leftarg, rightarg) - END -$$ -LANGUAGE SQL STABLE; +CREATE OR REPLACE FUNCTION sys.babelfish_concat_wrapper(leftarg text, rightarg text) RETURNS TEXT +AS 'babelfishpg_tsql', 'babelfish_concat_wrapper' +LANGUAGE C STABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.babelfish_concat_wrapper_outer(leftarg text, rightarg text) RETURNS sys.varchar(8000) AS $$ diff --git a/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.0.0--2.1.0.sql b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.0.0--2.1.0.sql index e63b72c5fa..df1879bf55 100644 --- a/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.0.0--2.1.0.sql +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.0.0--2.1.0.sql @@ -55,19 +55,5 @@ SELECT sys.babelfish_update_server_collation_name(); DROP FUNCTION sys.babelfish_update_server_collation_name(); --- And reset babelfishpg_tsql.restored_server_collation_name and babelfishpg_tsql.restored_default_locale GUC -do -language plpgsql -$$ - declare - query text; - begin - query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); - execute query; - query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_default_locale', CURRENT_DATABASE()); - execute query; - end; -$$; - -- 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_common/sql/upgrades/babelfishpg_common--2.3.0--3.0.0.sql b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.3.0--3.0.0.sql index f0592bede8..1e28260b0d 100644 --- a/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.3.0--3.0.0.sql +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.3.0--3.0.0.sql @@ -12,18 +12,5 @@ SELECT sys.babelfish_update_server_collation_name(); DROP FUNCTION sys.babelfish_update_server_collation_name(); --- And reset babelfishpg_tsql.restored_server_collation_name GUC -do -language plpgsql -$$ - declare - query text; - begin - query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); - execute query; - end; -$$; - - -- 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/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.4.0--3.0.0.sql b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.4.0--3.0.0.sql index f0592bede8..1e28260b0d 100644 --- a/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.4.0--3.0.0.sql +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.4.0--3.0.0.sql @@ -12,18 +12,5 @@ SELECT sys.babelfish_update_server_collation_name(); DROP FUNCTION sys.babelfish_update_server_collation_name(); --- And reset babelfishpg_tsql.restored_server_collation_name GUC -do -language plpgsql -$$ - declare - query text; - begin - query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); - execute query; - end; -$$; - - -- 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/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.5.0--3.0.0.sql b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.5.0--3.0.0.sql new file mode 100644 index 0000000000..1e28260b0d --- /dev/null +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--2.5.0--3.0.0.sql @@ -0,0 +1,16 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_common"" UPDATE TO '3.0.0'" to load this file. \quit + +SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); + +/* This helper function would only be useful and strictly be used during 1.x->2.3 and 2.3->3.0 upgrade. */ +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- 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/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..d9f108e3ff --- /dev/null +++ b/contrib/babelfishpg_common/sql/upgrades/babelfishpg_common--3.1.0--3.2.0.sql @@ -0,0 +1,46 @@ +-- 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; + +CREATE OR REPLACE FUNCTION sys.int4varbinarydiv(leftarg int4 , rightarg sys.bbf_varbinary) +RETURNS int4 +AS 'babelfishpg_common', 'int4varbinary_div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +DO $$ +BEGIN +IF NOT EXISTS(Select 1 from pg_operator where oprname = '/' and oprcode = 'sys.int4varbinarydiv'::regproc) THEN +CREATE OPERATOR sys./ ( + LEFTARG = int4, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = int4varbinarydiv, + COMMUTATOR = / +); +END IF; +END $$; + + + +CREATE OR REPLACE FUNCTION sys.varbinaryint4div(leftarg sys.bbf_varbinary , rightarg int4) +RETURNS int4 +AS 'babelfishpg_common', 'varbinaryint4_div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +DO $$ +BEGIN +IF NOT EXISTS(Select 1 from pg_operator where oprname = '/' and oprcode = 'sys.varbinaryint4div'::regproc) THEN +CREATE OPERATOR sys./ ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = int4, + FUNCTION = varbinaryint4div, + COMMUTATOR = / +); +END IF; +END $$; + +-- 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_common/sql/varbinary.sql b/contrib/babelfishpg_common/sql/varbinary.sql index 3c096717fa..5c1aabcefe 100644 --- a/contrib/babelfishpg_common/sql/varbinary.sql +++ b/contrib/babelfishpg_common/sql/varbinary.sql @@ -287,6 +287,35 @@ CREATE OPERATOR sys.<= ( COMMUTATOR = >= ); + +CREATE OR REPLACE FUNCTION sys.int4varbinarydiv(leftarg int4 , rightarg sys.bbf_varbinary) +RETURNS int4 +AS 'babelfishpg_common', 'int4varbinary_div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE OPERATOR sys./ ( + LEFTARG = int4, + RIGHTARG = sys.bbf_varbinary, + FUNCTION = int4varbinarydiv, + COMMUTATOR = / +); + +CREATE OR REPLACE FUNCTION sys.varbinaryint4div(leftarg sys.bbf_varbinary , rightarg int4) +RETURNS int4 +AS 'babelfishpg_common', 'varbinaryint4_div' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + + +CREATE OPERATOR sys./ ( + LEFTARG = sys.bbf_varbinary, + RIGHTARG = int4, + FUNCTION = varbinaryint4div, + COMMUTATOR = / +); + + + CREATE FUNCTION sys.bbf_varbinary_cmp(sys.bbf_varbinary, sys.bbf_varbinary) RETURNS int AS 'babelfishpg_common', 'varbinary_cmp' diff --git a/contrib/babelfishpg_common/sql/varchar.sql b/contrib/babelfishpg_common/sql/varchar.sql index 9058330f2b..7319ec8427 100644 --- a/contrib/babelfishpg_common/sql/varchar.sql +++ b/contrib/babelfishpg_common/sql/varchar.sql @@ -240,6 +240,7 @@ CREATE OR REPLACE AGGREGATE sys.max(sys.VARCHAR) sfunc = sys.varchar_larger, stype = sys.varchar, combinefunc = sys.varchar_larger, + sortop = >, parallel = safe ); @@ -248,6 +249,7 @@ CREATE OR REPLACE AGGREGATE sys.min(sys.VARCHAR) sfunc = sys.varchar_smaller, stype = sys.varchar, combinefunc = sys.varchar_smaller, + sortop = <, parallel = safe ); diff --git a/contrib/babelfishpg_common/src/babelfishpg_common.c b/contrib/babelfishpg_common/src/babelfishpg_common.c index 47afcc99b5..9de84ec778 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" @@ -18,6 +18,7 @@ #include "sqlvariant.h" #include "typecode.h" #include "varchar.h" +#include "datetimeoffset.h" common_utility_plugin common_utility_plugin_var = {NULL}; static common_utility_plugin *get_common_utility_plugin(void); @@ -25,51 +26,61 @@ 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; +set_like_collation_hook_type prev_set_like_collation_hook = NULL; +get_like_collation_hook_type prev_get_like_collation_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 +90,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 +103,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; @@ -131,6 +142,12 @@ _PG_init(void) prev_PreCreateCollation_hook = PreCreateCollation_hook; PreCreateCollation_hook = BabelfishPreCreateCollation_hook; + + prev_set_like_collation_hook = set_like_collation_hook; + set_like_collation_hook = bbf_set_like_collation; + prev_get_like_collation_hook = get_like_collation_hook; + get_like_collation_hook = bbf_get_like_collation; + } void _PG_fini(void) @@ -141,12 +158,14 @@ _PG_fini(void) CLUSTER_COLLATION_OID_hook = prev_CLUSTER_COLLATION_OID_hook; TranslateCollation_hook = prev_TranslateCollation_hook; PreCreateCollation_hook = prev_PreCreateCollation_hook; + set_like_collation_hook = prev_set_like_collation_hook; + get_like_collation_hook = prev_get_like_collation_hook; } 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; @@ -160,7 +179,9 @@ get_common_utility_plugin(void) common_utility_plugin_var.is_tsql_ntext_datatype = &is_tsql_ntext_datatype; common_utility_plugin_var.is_tsql_image_datatype = &is_tsql_image_datatype; common_utility_plugin_var.is_tsql_binary_datatype = &is_tsql_binary_datatype; + common_utility_plugin_var.is_tsql_sys_binary_datatype = &is_tsql_sys_binary_datatype; common_utility_plugin_var.is_tsql_varbinary_datatype = &is_tsql_varbinary_datatype; + common_utility_plugin_var.is_tsql_sys_varbinary_datatype = &is_tsql_sys_varbinary_datatype; common_utility_plugin_var.is_tsql_timestamp_datatype = &is_tsql_timestamp_datatype; common_utility_plugin_var.is_tsql_datetime2_datatype = &is_tsql_datetime2_datatype; common_utility_plugin_var.is_tsql_smalldatetime_datatype = &is_tsql_smalldatetime_datatype; @@ -169,14 +190,17 @@ get_common_utility_plugin(void) common_utility_plugin_var.is_tsql_rowversion_or_timestamp_datatype = &is_tsql_rowversion_or_timestamp_datatype; common_utility_plugin_var.datetime_in_str = &datetime_in_str; common_utility_plugin_var.datetime2sqlvariant = &datetime2sqlvariant; + common_utility_plugin_var.timestamp_datetimeoffset = ×tamp_datetimeoffset; common_utility_plugin_var.tinyint2sqlvariant = &tinyint2sqlvariant; common_utility_plugin_var.translate_pg_type_to_tsql = &translate_pg_type_to_tsql; + common_utility_plugin_var.get_tsql_datatype_oid = &get_tsql_datatype_oid; common_utility_plugin_var.TdsGetPGbaseType = &TdsGetPGbaseType; common_utility_plugin_var.TdsSetMetaData = &TdsSetMetaData; common_utility_plugin_var.TdsPGbaseType = &TdsPGbaseType; common_utility_plugin_var.TdsGetMetaData = &TdsGetMetaData; common_utility_plugin_var.TdsGetVariantBaseType = &TdsGetVariantBaseType; common_utility_plugin_var.lookup_tsql_datatype_oid = &lookup_tsql_datatype_oid; + common_utility_plugin_var.GetUTF8CodePoint = &GetUTF8CodePoint; } return &common_utility_plugin_var; } diff --git a/contrib/babelfishpg_common/src/babelfishpg_common.h b/contrib/babelfishpg_common/src/babelfishpg_common.h index 154be7bf37..d7c7cd74ae 100644 --- a/contrib/babelfishpg_common/src/babelfishpg_common.h +++ b/contrib/babelfishpg_common/src/babelfishpg_common.h @@ -2,42 +2,73 @@ #include "fmgr.h" +/* + * Casting float < -1.0 to unsigned integer could cause issues on ARM. + * + * For instance: + * auto fvalue = -176.0; + * auto tvalue = static_cast(fvalue); + * On Intel, tvalue = 65360 which is correct. + * On ARM, tvalue = 0 which is wrong. + * + * Hence the compiler flag -Wfloat-conversion has been added to BBF Makefiles + * to guard the codebase from this bug. + * + * However, float-conversion is not too granular enough because it also + * flags things like float8 to float4 conversion or conversions where the + * original value is always greater than or equal to zero. + * For code that are being flagged but are not really an issue, we can suppress + * the compilation error by surrounding them with _Pragma(). + */ +#define BBF_Pragma_IgnoreFloatConversionWarning_Push \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wfloat-conversion\"") + +#define BBF_Pragma_IgnoreFloatConversionWarning_Pop \ + _Pragma("GCC diagnostic pop") + 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_sys_binary_datatype) (Oid oid); + bool (*is_tsql_sys_varbinary_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 (*timestamp_datetimeoffset) (PG_FUNCTION_ARGS); + Datum (*tinyint2sqlvariant) (PG_FUNCTION_ARGS); + Datum (*translate_pg_type_to_tsql) (PG_FUNCTION_ARGS); + Oid (*get_tsql_datatype_oid) (char *type_name); + 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); + int32_t (*GetUTF8CodePoint) (const unsigned char *in, int len, int *consumed_p); + +} 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..1afd331b04 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" @@ -28,7 +28,7 @@ #include "utils/memutils.h" #include "utils/lsyscache.h" #include "utils/syscache.h" - +#include "babelfishpg_common.h" // BBF_Pragma_IgnoreFloatConversionWarning_Push #include @@ -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,9 @@ inline static float8 dtrunc_(float8 arg1) return result; } -inline static float4 ftrunc_(float4 arg1) +BBF_Pragma_IgnoreFloatConversionWarning_Push +inline static float4 +ftrunc_(float4 arg1) { float8 result; @@ -63,6 +66,7 @@ inline static float4 ftrunc_(float4 arg1) return result; } +BBF_Pragma_IgnoreFloatConversionWarning_Pop /* dtrunci8(X) = dtoi8(dtrunc(X)) */ PG_FUNCTION_INFO_V1(dtrunci8); @@ -70,7 +74,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 +99,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 +124,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,14 +149,16 @@ 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 * on just-out-of-range values that would round into range. Note * assumption that rint() will pass through a NaN or Inf unchanged. */ + BBF_Pragma_IgnoreFloatConversionWarning_Push num = rint(ftrunc_(num)); + BBF_Pragma_IgnoreFloatConversionWarning_Pop /* Range check */ if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT64(num))) @@ -164,20 +170,24 @@ ftrunci8(PG_FUNCTION_ARGS) } + + /* ftrunci4(X) = ftoi4(ftrunc(X)) */ 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 * on just-out-of-range values that would round into range. Note * assumption that rint() will pass through a NaN or Inf unchanged. */ + BBF_Pragma_IgnoreFloatConversionWarning_Push num = rint(ftrunc_(num)); + BBF_Pragma_IgnoreFloatConversionWarning_Pop /* Range check */ if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT32(num))) @@ -188,21 +198,22 @@ ftrunci4(PG_FUNCTION_ARGS) PG_RETURN_INT32((int32) num); } - /* ftrunci2(X) = ftoi2(ftrunc(X)) */ 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 * on just-out-of-range values that would round into range. Note * assumption that rint() will pass through a NaN or Inf unchanged. */ + BBF_Pragma_IgnoreFloatConversionWarning_Push num = rint(ftrunc_(num)); + BBF_Pragma_IgnoreFloatConversionWarning_Pop /* Range check */ if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT16(num))) @@ -222,9 +233,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 +243,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } @@ -272,10 +284,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 +296,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 +312,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + 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..218f79c18b 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) { @@ -1528,3 +1587,15 @@ babelfish_update_server_collation_name(PG_FUNCTION_ARGS) MemoryContextSwitchTo(oldContext); PG_RETURN_VOID(); } + +Oid like_cid = InvalidOid; + +void bbf_set_like_collation(Oid collation) +{ + like_cid = collation; +} + +Oid bbf_get_like_collation(void) +{ + return like_cid; +} diff --git a/contrib/babelfishpg_common/src/collation.h b/contrib/babelfishpg_common/src/collation.h index 72043d7b89..c74330210c 100644 --- a/contrib/babelfishpg_common/src/collation.h +++ b/contrib/babelfishpg_common/src/collation.h @@ -21,137 +21,147 @@ 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; + +extern set_like_collation_hook_type prev_set_like_collation_hook; +extern get_like_collation_hook_type prev_get_like_collation_hook; + +extern void bbf_set_like_collation(Oid collation); +extern Oid bbf_get_like_collation(void); diff --git a/contrib/babelfishpg_common/src/datetime.c b/contrib/babelfishpg_common/src/datetime.c index f977e285f7..7bcacd2ef5 100644 --- a/contrib/babelfishpg_common/src/datetime.c +++ b/contrib/babelfishpg_common/src/datetime.c @@ -12,9 +12,11 @@ #include "utils/builtins.h" #include "utils/date.h" #include "utils/datetime.h" +#include "utils/numeric.h" #include "utils/timestamp.h" #include "libpq/pqformat.h" - +#include "parser/scansup.h" +#include "common/int.h" #include "miscadmin.h" #include "datetime.h" @@ -43,8 +45,22 @@ 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); +PG_FUNCTION_INFO_V1(datetime_to_bit); +PG_FUNCTION_INFO_V1(datetime_to_int2); +PG_FUNCTION_INFO_V1(datetime_to_int4); +PG_FUNCTION_INFO_V1(datetime_to_int8); +PG_FUNCTION_INFO_V1(datetime_to_float4); +PG_FUNCTION_INFO_V1(datetime_to_float8); +PG_FUNCTION_INFO_V1(datetime_to_numeric); + +PG_FUNCTION_INFO_V1(dateadd_datetime); +PG_FUNCTION_INFO_V1(timestamp_diff); +PG_FUNCTION_INFO_V1(timestamp_diff_big); + +void CheckDatetimeRange(const Timestamp time); +void CheckDatetimePrecision(fsec_t fsec); + +#define DTK_NANO 32 Datum datetime_in_str(char *str) @@ -65,7 +81,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 +94,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 +131,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 +151,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 +173,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 +194,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 +208,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 +242,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 +268,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 +323,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 +343,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 +367,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 +387,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 +396,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 +424,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 +437,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 +473,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 +486,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 +497,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 +518,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 +531,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 +556,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 +583,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 +598,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 +613,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 +628,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 +644,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 +656,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,17 +682,704 @@ 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; CheckDatetimeRange(result); PG_RETURN_TIMESTAMP(result); } + +/* +* Common Utility function to calculate days elapsed from 1900-01-01 00:00:00 (default datetime) +* Days will contains whole as well as fractional part +*/ +float8 +calculateDaysFromDefaultDatetime(Timestamp timestamp_left) +{ + Timestamp timestamp_right; + Interval *result_interval; + struct pg_itm tt, *itm = &tt; + float8 result; + int fsec_rounded = 0; + + timestamp_right = DirectFunctionCall6(make_timestamp, 1900, 1, 1, 0, 0, 0); + result_interval = (Interval *) DirectFunctionCall2(timestamp_mi, timestamp_left, timestamp_right); + interval2itm(*result_interval, itm); + fsec_rounded = roundFractionalSeconds(itm->tm_usec/1000) * 1000; + result = result_interval->day + (float8) (itm->tm_hour * USECS_PER_HOUR + itm->tm_min * USECS_PER_MINUTE + itm->tm_sec * USECS_PER_SEC + fsec_rounded)/(float8) USECS_PER_DAY; + return result; +} + +/** round datetime fractional seconds to fixed bins */ +int roundFractionalSeconds(int v_fractseconds) +{ + int v_modpart; + int v_decpart; + v_modpart = v_fractseconds % 10; + v_decpart = v_fractseconds - v_modpart; + + switch (v_modpart) + { + case 0: + case 1: + return v_decpart; + case 2: + case 3: + case 4: + return v_decpart + 3; + case 5: + case 6: + case 7: + case 8: + return v_decpart + 7; + default: + return v_decpart + 10; + } + +} + +Datum +datetime_to_bit(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_BOOL((bool)result); +} + +Datum +datetime_to_int2(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_INT16((int16)round(result)); +} + + +Datum +datetime_to_int4(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_INT32((int32)round(result)); +} + +Datum +datetime_to_int8(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_INT64((int64)round(result)); +} + +Datum +datetime_to_float4(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_FLOAT4((float4)result); +} + +Datum +datetime_to_float8(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_FLOAT8((float8)result); +} + +Datum +datetime_to_numeric(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_NUMERIC(DirectFunctionCall1(float8_numeric, Float8GetDatum(result))); +} + +/* + * Returns the difference of two timestamps based on a provided unit + * INT64 representation for bigints + */ +Datum +timestamp_diff(PG_FUNCTION_ARGS) +{ + + text *field = PG_GETARG_TEXT_PP(0); + Timestamp timestamp1 = PG_GETARG_TIMESTAMP(1); + Timestamp timestamp2 = PG_GETARG_TIMESTAMP(2); + int32 diff = -1; + int tm1Valid; + int tm2Valid; + int32 yeardiff; + int32 monthdiff; + int32 daydiff; + int32 hourdiff; + int32 minutediff; + int32 seconddiff; + int32 millisecdiff; + int32 microsecdiff; + struct pg_tm tt1, + *tm1 = &tt1; + fsec_t fsec1; + struct pg_tm tt2, + *tm2 = &tt2; + fsec_t fsec2; + int type, + val; + char *lowunits; + bool overflow = false; + bool validDateDiff = true; + + tm1Valid = timestamp2tm(timestamp1, NULL, tm1, &fsec1, NULL, NULL); + tm2Valid = timestamp2tm(timestamp2, NULL, tm2, &fsec2, NULL, NULL); + + lowunits = downcase_truncate_identifier(VARDATA_ANY(field), + VARSIZE_ANY_EXHDR(field), + false); + + type = DecodeUnits(0, lowunits, &val); + + // Decode units does not handle doy properly + if(strncmp(lowunits, "doy", 3) == 0) { + type = UNITS; + val = DTK_DOY; + } + + if(strncmp(lowunits, "nanosecond", 11) == 0) { + type = UNITS; + val = DTK_NANO; + } + if(strncmp(lowunits, "weekday", 7) == 0) { + type = UNITS; + val = DTK_DAY; + } + + if(type == UNITS) { + if(tm1Valid == 0 && tm2Valid == 0) { + switch(val) { + case DTK_YEAR: + diff = tm2->tm_year - tm1->tm_year; + break; + case DTK_QUARTER: + yeardiff = tm2->tm_year - tm1->tm_year; + monthdiff = tm2->tm_mon - tm1->tm_mon; + diff = (yeardiff * 12 + monthdiff) / 3; + break; + case DTK_MONTH: + yeardiff = tm2->tm_year - tm1->tm_year; + monthdiff = tm2->tm_mon - tm1->tm_mon; + diff = yeardiff * 12 + monthdiff; + break; + case DTK_WEEK: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + diff = daydiff / 7; + if(daydiff % 7 >= 4) + diff++; + break; + case DTK_DAY: + case DTK_DOY: + diff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + break; + case DTK_HOUR: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + overflow = (overflow || !(int32_multiply_add(daydiff, 24, &hourdiff))); + diff = hourdiff; + break; + case DTK_MINUTE: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + overflow = (overflow || !(int32_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int32_multiply_add(hourdiff, 60, &minutediff))); + diff = minutediff; + break; + case DTK_SECOND: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + overflow = (overflow || !(int32_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int32_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int32_multiply_add(minutediff, 60, &seconddiff))); + diff = seconddiff; + break; + case DTK_MILLISEC: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + millisecdiff = (fsec2 / 1000) - (fsec1 / 1000); + overflow = (overflow || !(int32_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int32_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int32_multiply_add(minutediff, 60, &seconddiff))); + overflow = (overflow || !(int32_multiply_add(seconddiff, 1000, &millisecdiff))); + diff = millisecdiff; + break; + case DTK_MICROSEC: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + microsecdiff = fsec2 - fsec1; + overflow = (overflow || !(int32_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int32_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int32_multiply_add(minutediff, 60, &seconddiff))); + overflow = (overflow || !(int32_multiply_add(seconddiff, 1000000, µsecdiff))); + diff = microsecdiff; + break; + case DTK_NANO: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + microsecdiff = fsec2 - fsec1; + overflow = (overflow || !(int32_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int32_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int32_multiply_add(minutediff, 60, &seconddiff))); + overflow = (overflow || !(int32_multiply_add(seconddiff, 1000000, µsecdiff))); + overflow = (overflow || (pg_mul_s32_overflow(microsecdiff, 1000, &diff))); + break; + default: + validDateDiff = false; + break; + } + } + else { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + } + } else { + validDateDiff = false; + } + + if(!validDateDiff) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\'%s\' is not a recognized %s option", lowunits, "datediff"))); + } + if(overflow) { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart"))); + } + + PG_RETURN_INT32(diff); +} + +/* + * Returns the difference of two timestamps based on a provided unit + * INT64 representation for bigints + */ +Datum +timestamp_diff_big(PG_FUNCTION_ARGS) +{ + text *field = PG_GETARG_TEXT_PP(0); + Timestamp timestamp1 = PG_GETARG_TIMESTAMP(1); + Timestamp timestamp2 = PG_GETARG_TIMESTAMP(2); + int64 diff = -1; + int tm1Valid; + int tm2Valid; + int64 yeardiff; + int64 monthdiff; + int64 daydiff; + int64 hourdiff; + int64 minutediff; + int64 seconddiff; + int64 millisecdiff; + int64 microsecdiff; + struct pg_tm tt1, + *tm1 = &tt1; + fsec_t fsec1; + struct pg_tm tt2, + *tm2 = &tt2; + fsec_t fsec2; + int type, + val; + char *lowunits; + bool overflow = false; + bool validDateDiff = true; + + tm1Valid = timestamp2tm(timestamp1, NULL, tm1, &fsec1, NULL, NULL); + tm2Valid = timestamp2tm(timestamp2, NULL, tm2, &fsec2, NULL, NULL); + + lowunits = downcase_truncate_identifier(VARDATA_ANY(field), + VARSIZE_ANY_EXHDR(field), + false); + + type = DecodeUnits(0, lowunits, &val); + + // Decode units does not handle doy or nano properly + if(strncmp(lowunits, "doy", 3) == 0) { + type = UNITS; + val = DTK_DOY; + } + if(strncmp(lowunits, "nanosecond", 11) == 0) { + type = UNITS; + val = DTK_NANO; + } + if(strncmp(lowunits, "weekday", 7) == 0) { + type = UNITS; + val = DTK_DAY; + } + + if(type == UNITS) { + if(tm1Valid == 0 && tm2Valid == 0) { + switch(val) + { + case DTK_YEAR: + diff = tm2->tm_year - tm1->tm_year; + break; + case DTK_QUARTER: + yeardiff = tm2->tm_year - tm1->tm_year; + monthdiff = tm2->tm_mon - tm1->tm_mon; + diff = (yeardiff * 12 + monthdiff) / 3; + break; + case DTK_MONTH: + yeardiff = tm2->tm_year - tm1->tm_year; + monthdiff = tm2->tm_mon - tm1->tm_mon; + diff = yeardiff * 12 + monthdiff; + break; + case DTK_WEEK: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + diff = daydiff / 7; + if(daydiff % 7 >= 4) + diff++; + break; + case DTK_DAY: + case DTK_DOY: + diff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + break; + case DTK_HOUR: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + overflow = (overflow || !(int64_multiply_add(daydiff, 24, &hourdiff))); + diff = hourdiff; + break; + case DTK_MINUTE: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + overflow = (overflow || !(int64_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int64_multiply_add(hourdiff, 60, &minutediff))); + diff = minutediff; + break; + case DTK_SECOND: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + overflow = (overflow || !(int64_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int64_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int64_multiply_add(minutediff, 60, &seconddiff))); + diff = seconddiff; + break; + case DTK_MILLISEC: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + millisecdiff = (fsec2 / 1000) - (fsec1 / 1000); + overflow = (overflow || !(int64_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int64_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int64_multiply_add(minutediff, 60, &seconddiff))); + overflow = (overflow || !(int64_multiply_add(seconddiff, 1000, &millisecdiff))); + diff = millisecdiff; + break; + case DTK_MICROSEC: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + microsecdiff = fsec2 - fsec1; + overflow = (overflow || !(int64_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int64_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int64_multiply_add(minutediff, 60, &seconddiff))); + overflow = (overflow || !(int64_multiply_add(seconddiff, 1000000, µsecdiff))); + diff = microsecdiff; + break; + case DTK_NANO: + daydiff = days_in_date(tm2->tm_mday, tm2->tm_mon, tm2->tm_year) - days_in_date(tm1->tm_mday, tm1->tm_mon, tm1->tm_year); + hourdiff = tm2->tm_hour - tm1->tm_hour; + minutediff = tm2->tm_min - tm1->tm_min; + seconddiff = tm2->tm_sec - tm1->tm_sec; + microsecdiff = fsec2 - fsec1; + overflow = (overflow || !(int64_multiply_add(daydiff, 24, &hourdiff))); + overflow = (overflow || !(int64_multiply_add(hourdiff, 60, &minutediff))); + overflow = (overflow || !(int64_multiply_add(minutediff, 60, &seconddiff))); + overflow = (overflow || !(int64_multiply_add(seconddiff, 1000000, µsecdiff))); + overflow = (overflow || (pg_mul_s64_overflow(microsecdiff, 1000, &diff))); + break; + default: + validDateDiff = false; + } + } + else { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + } + } else { + validDateDiff = false; + } + + if(!validDateDiff) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\'%s\' is not a recognized %s option", lowunits, "datediff"))); + } + if(overflow) { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart"))); + } + + PG_RETURN_INT64(diff); +} + +bool +int64_multiply_add(int64 val, int64 multiplier, int64 *sum) +{ + int64 product; + + if (pg_mul_s64_overflow(val, multiplier, &product) || + pg_add_s64_overflow(*sum, product, sum)) + return false; + return true; +} + +bool +int32_multiply_add(int32 val, int32 multiplier, int32 *sum) +{ + int32 product; + + if (pg_mul_s32_overflow(val, multiplier, &product) || + pg_add_s32_overflow(*sum, product, sum)) + return false; + return true; +} + +int days_in_date(int day, int month, int year) { + int n1 = year * 365 + day; + for(int i = 1; i < month; i++) { + if(i == 2) + n1 += 28; + else if(i == 4 || i == 6 || i == 9 || i == 11) + n1 += 30; + else + n1 += 31; + } + if(month <= 2) + year -= 1; + n1 += (year / 4 - year / 100 + year / 400); + return n1; +} + +char *datetypeName(int num) { + char* ret; + switch(num) { + case 0: + ret = "time"; + break; + case 1: + ret = "date"; + break; + case 2: + ret = "smalldatetime"; + break; + case 3: + ret = "datetime"; + break; + case 4: + ret = "datetime2"; + break; + default: + ret = "unknown"; + } + return ret; +} + +Datum +dateadd_datetime(PG_FUNCTION_ARGS) { + text *field = PG_GETARG_TEXT_PP(0); + int num = PG_GETARG_INT32(1); + enum Datetimetype { + TIME, + DATE, + SMALLDATETIME, + DATETIME, + DATETIME2 + }; + Timestamp timestamp; + enum Datetimetype dttype = PG_GETARG_INT32(3); + char *lowunits; + int type, + val; + Timestamp result; + Interval *interval; + bool validDateAdd = true; + bool incompatibleDatePart = false; + + switch(dttype) { + case TIME: + timestamp = DirectFunctionCall1(time_datetime, (TimeADT) PG_GETARG_TIMEADT(2)); + break; + case DATE: + timestamp = DirectFunctionCall1(date_datetime, (DateADT) PG_GETARG_DATEADT(2)); + break; + default: + timestamp = PG_GETARG_TIMESTAMP(2); + } + + lowunits = downcase_truncate_identifier(VARDATA_ANY(field), + VARSIZE_ANY_EXHDR(field), + false); + + type = DecodeUnits(0, lowunits, &val); + + if(strncmp(lowunits, "doy", 3) == 0 || strncmp(lowunits, "dayofyear", 9) == 0) { + type = UNITS; + val = DTK_DOY; + } + if(strncmp(lowunits, "nanosecond", 11) == 0) { + type = UNITS; + val = DTK_NANO; + } + if(strncmp(lowunits, "weekday", 7) == 0) { + type = UNITS; + val = DTK_DAY; + } + + + if(type == UNITS) { + switch(val) { + case DTK_YEAR: + if(dttype == TIME) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, num, 0, 0, 0, 0, 0, 0); + break; + case DTK_QUARTER: + if(dttype == TIME) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, num * 3, 0, 0, 0, 0, 0); + break; + case DTK_MONTH: + if(dttype == TIME) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, num, 0, 0, 0, 0, 0); + break; + case DTK_WEEK: + if(dttype == TIME) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, num, 0, 0, 0, 0); + break; + case DTK_DAY: + case DTK_DOY: + if(dttype == TIME) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, num, 0, 0, 0); + break; + case DTK_HOUR: + if(dttype == DATE) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, num, 0, 0); + break; + case DTK_MINUTE: + if(dttype == DATE) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, num, 0); + break; + case DTK_SECOND: + if(dttype == DATE) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum(num)); + break; + case DTK_MILLISEC: + if(dttype == DATE) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.001)); + break; + case DTK_MICROSEC: + if(dttype == SMALLDATETIME || dttype == DATETIME || dttype == DATE) { + incompatibleDatePart = true; + break; + } + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.000001)); + break; + case DTK_NANO: + if(dttype == SMALLDATETIME || dttype == DATETIME || dttype == DATE) { + incompatibleDatePart = true; + break; + } + num = num / 1000 * 1000; // Floors the number to avoid incorrect rounding + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.000000001)); + break; + default: + validDateAdd = false; + break; + } + } else { + validDateAdd = false; + } + + if(incompatibleDatePart) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("The datepart %s is not supported by date function %s for data type %s.", lowunits, "dateadd", datetypeName(dttype)))); + } + + if(!validDateAdd) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\'%s\' is not a recognized %s option", lowunits, "dateadd"))); + } + + PG_TRY(); + { + result = DirectFunctionCall2(timestamp_pl_interval, timestamp, PointerGetDatum(interval)); + + /* + * This check is required because the range of valid timestamps + * is greater than the range of valid datetimes + */ + CheckDatetimeRange(result); + } + PG_CATCH(); + { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("Adding a value to a \'%s\' column caused an overflow.", datetypeName(dttype)))); + } + PG_END_TRY(); + + PG_RETURN_TIMESTAMP(result); +} diff --git a/contrib/babelfishpg_common/src/datetime.h b/contrib/babelfishpg_common/src/datetime.h index 6a021e05c1..592677cb05 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 */ @@ -28,6 +28,15 @@ #define END_DATETIME INT64CONST(252455615999999000) extern Timestamp initializeToDefaultDatetime(void); +/** Utility function to calculate days from '1900-01-01 00:00:00' */ +extern double calculateDaysFromDefaultDatetime(Timestamp timestamp_left); +extern int roundFractionalSeconds(int fractseconds); + +extern int days_in_date(int day, int month, int year); +extern char* datetypeName(int num); + +extern bool int64_multiply_add(int64 val, int64 multiplier, int64 *sum); +extern bool int32_multiply_add(int32 val, int32 multiplier, int32 *sum); /* Range-check a datetime */ #define IS_VALID_DATETIME(t) (MIN_DATETIME <= (t) && (t) < END_DATETIME) diff --git a/contrib/babelfishpg_common/src/datetime2.c b/contrib/babelfishpg_common/src/datetime2.c index 268d69c046..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,75 +139,79 @@ 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) { - 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) }; - int64 adjustedTime; + int64 adjustedTime; 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)) - { + { 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]; } @@ -230,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"))); } } @@ -263,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); } @@ -289,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); } @@ -332,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); } @@ -374,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); } @@ -415,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..1041e0e2c5 100644 --- a/contrib/babelfishpg_common/src/datetimeoffset.c +++ b/contrib/babelfishpg_common/src/datetimeoffset.c @@ -13,6 +13,7 @@ #include "utils/datetime.h" #include "libpq/pqformat.h" #include "utils/timestamp.h" +#include "parser/scansup.h" #include "fmgr.h" #include "miscadmin.h" @@ -20,9 +21,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); @@ -63,6 +64,9 @@ PG_FUNCTION_INFO_V1(datetimeoffset_datetime2); PG_FUNCTION_INFO_V1(datetimeoffset_scale); PG_FUNCTION_INFO_V1(get_datetimeoffset_tzoffset_internal); +PG_FUNCTION_INFO_V1(dateadd_datetimeoffset); + +#define DTK_NANO 32 /* datetimeoffset_in() @@ -79,8 +83,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 +96,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 +116,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,12 +128,20 @@ datetimeoffset_in(PG_FUNCTION_ARGS) if (dterr != 0) DateTimeParseError(dterr, str, "timestamp with time zone"); - datetimeoffset->tsql_tz = (int16)(tz/60); - tz = 0; + /* + * When time zone offset it not specified in input string + * DecodeDateTime sets it to the session time zone. + * In T-SQL it must default to '+00:00', not to session time zone. + */ + if (nf > 0 && ftype[nf - 1] == DTK_TZ) + datetimeoffset->tsql_tz = (int16) (tz / 60); + else + datetimeoffset->tsql_tz = 0; + switch (dtype) { case DTK_DATE: - if (tm2timestamp(tm, fsec, &tz, &tsql_ts) != 0) + if (tm2timestamp(tm, fsec, NULL, &tsql_ts) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range: \"%s\"", str))); @@ -150,7 +165,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 +177,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 +210,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 +235,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 +247,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 +326,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 +368,18 @@ 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; - int tz; + Timestamp tmp = df->tsql_ts; if (span->month != 0) { struct pg_tm tt, - *tm = &tt; + *tm = &tt; fsec_t fsec; - if (timestamp2tm(tmp, &tz, tm, &fsec, NULL, NULL) != 0) + if (timestamp2tm(tmp, NULL, 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) @@ -381,34 +397,32 @@ datetimeoffset_pl_interval(PG_FUNCTION_ARGS) if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); - tz = 0; - if (tm2timestamp(tm, fsec, &tz, &tmp) != 0) + if (tm2timestamp(tm, fsec, NULL, &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) + if (timestamp2tm(tmp, NULL, 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; j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); - tz = 0; - if (tm2timestamp(tm, fsec, &tz, &tmp) != 0) + if (tm2timestamp(tm, fsec, NULL, &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 +465,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 +490,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 +500,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,8 +518,9 @@ Datum datetimeoffset_smalldatetime(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; - datetimeoffset_timestamp_internal(df, &result); + Timestamp result; + + result = df->tsql_ts; CheckSmalldatetimeRange(result); AdjustTimestampForSmallDatetime(&result); @@ -517,8 +533,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,8 +551,9 @@ Datum datetimeoffset_datetime(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; - datetimeoffset_timestamp_internal(df, &result); + Timestamp result; + + result = df->tsql_ts; CheckDatetimeRange(result); PG_RETURN_TIMESTAMP(result); @@ -548,8 +565,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,8 +583,9 @@ Datum datetimeoffset_datetime2(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp result; - datetimeoffset_timestamp_internal(df, &result); + Timestamp result; + + result = df->tsql_ts; CheckDatetime2Range(result); PG_RETURN_TIMESTAMP(result); @@ -579,8 +597,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 +615,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 +629,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,18 +646,17 @@ 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; - datetimeoffset_timestamp_internal(df, &time); - if (timestamp2tm(time, &tz, tm, &fsec, NULL, NULL) != 0) + time = df->tsql_ts; + if (timestamp2tm(time, NULL, 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,10 +670,10 @@ Datum datetimeoffset_time(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); - Timestamp time; + Timestamp time; TimeADT result; - datetimeoffset_timestamp_internal(df, &time); + time = df->tsql_ts; if (time < 0) result = time - (time / USECS_PER_DAY * USECS_PER_DAY) + USECS_PER_DAY; else @@ -703,6 +721,7 @@ Datum get_datetimeoffset_tzoffset_internal(PG_FUNCTION_ARGS) { tsql_datetimeoffset *df = PG_GETARG_DATETIMEOFFSET(0); + PG_RETURN_INT16(-df->tsql_tz); } @@ -711,10 +730,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 +745,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 +819,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++ = ' '; @@ -813,3 +836,104 @@ EncodeDatetimeoffsetTimezone(char *str, int tz, int style) *tmp = '\0'; } + +Datum +dateadd_datetimeoffset(PG_FUNCTION_ARGS) { + text *field = PG_GETARG_TEXT_PP(0); + int num = PG_GETARG_INT32(1); + tsql_datetimeoffset *init_startdate = PG_GETARG_DATETIMEOFFSET(2); + bool validDateAdd = true; + char *lowunits; + int type, + val; + tsql_datetimeoffset *result; + Interval *interval; + int timezone = DirectFunctionCall1(get_datetimeoffset_tzoffset_internal, DatetimeoffsetGetDatum(init_startdate)) * 2; + tsql_datetimeoffset *startdate = (tsql_datetimeoffset *) DirectFunctionCall2(datetimeoffset_pl_interval, DatetimeoffsetGetDatum(init_startdate), DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, timezone, 0)); + + + lowunits = downcase_truncate_identifier(VARDATA_ANY(field), + VARSIZE_ANY_EXHDR(field), + false); + + type = DecodeUnits(0, lowunits, &val); + + if(strncmp(lowunits, "doy", 3) == 0 || strncmp(lowunits, "dayofyear", 9) == 0) { + type = UNITS; + val = DTK_DOY; + } + + if(strncmp(lowunits, "nanosecond", 11) == 0) { + type = UNITS; + val = DTK_NANO; + } + if(strncmp(lowunits, "weekday", 7) == 0) { + type = UNITS; + val = DTK_DAY; + } + + if(type == UNITS) { + switch(val) { + case DTK_YEAR: + interval = (Interval *) DirectFunctionCall7(make_interval, num, 0, 0, 0, 0, 0, 0); + break; + case DTK_QUARTER: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, num * 3, 0, 0, 0, 0, 0); + break; + case DTK_MONTH: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, num, 0, 0, 0, 0, 0); + break; + case DTK_WEEK: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, num, 0, 0, 0, 0); + break; + case DTK_DAY: + case DTK_DOY: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, num, 0, 0, 0); + break; + case DTK_HOUR: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, num, 0, 0); + break; + case DTK_MINUTE: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, num, 0); + break; + case DTK_SECOND: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum(num)); + break; + case DTK_MILLISEC: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.001)); + break; + case DTK_MICROSEC: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.000001)); + break; + case DTK_NANO: + interval = (Interval *) DirectFunctionCall7(make_interval, 0, 0, 0, 0, 0, 0, Float8GetDatum((float) num * 0.000000001)); + break; + default: + validDateAdd = false; + break; + } + } else { + validDateAdd = false; + } + + if(!validDateAdd) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\'%s\' is not a recognized %s option", lowunits, "dateadd"))); + } + + PG_TRY(); + { + result = (tsql_datetimeoffset *) DirectFunctionCall2(datetimeoffset_pl_interval, DatetimeoffsetGetDatum(startdate), PointerGetDatum(interval)); + + } + PG_CATCH(); + { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("Adding a value to a \'%s\' column caused an overflow.", "datetimeoffset"))); + } + PG_END_TRY(); + + PG_RETURN_DATETIMEOFFSET(result); +} \ No newline at end of file diff --git a/contrib/babelfishpg_common/src/datetimeoffset.h b/contrib/babelfishpg_common/src/datetimeoffset.h index ae1c9d8e55..4fead652c5 100644 --- a/contrib/babelfishpg_common/src/datetimeoffset.h +++ b/contrib/babelfishpg_common/src/datetimeoffset.h @@ -23,10 +23,11 @@ extern void AdjustTimestampForSmallDatetime(Timestamp *time); extern void CheckSmalldatetimeRange(const Timestamp time); extern void CheckDatetimeRange(const Timestamp time); extern void CheckDatetime2Range(const Timestamp time); +extern Datum timestamp_datetimeoffset(PG_FUNCTION_ARGS); 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..9ba55a7694 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 tsql_utf8_to_win(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_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 tsql_win_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_big5_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len); +extern int tsql_gbk_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_uhc_to_utf8(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *result, int len); +extern int tsql_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..e2540faf92 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,20 +100,20 @@ do_encoding_conversion(unsigned char *src, int len, { switch (dest_encoding) { - case PG_BIG5: - *encodedByteLen = utf8_to_big5(src_encoding, dest_encoding, src, result, len); + case PG_BIG5: + *encodedByteLen = tsql_utf8_to_big5(src_encoding, dest_encoding, src, result, len); break; - case PG_GBK: - *encodedByteLen = utf8_to_gbk(src_encoding, dest_encoding, src, result, len); + case PG_GBK: + *encodedByteLen = tsql_utf8_to_gbk(src_encoding, dest_encoding, src, result, len); break; - case PG_UHC: - *encodedByteLen = utf8_to_uhc(src_encoding, dest_encoding, src, result, len); + case PG_UHC: + *encodedByteLen = tsql_utf8_to_uhc(src_encoding, dest_encoding, src, result, len); break; - case PG_SJIS: - *encodedByteLen = utf8_to_sjis(src_encoding, dest_encoding, src, result, len); + case PG_SJIS: + *encodedByteLen = tsql_utf8_to_sjis(src_encoding, dest_encoding, src, result, len); break; - default: - *encodedByteLen = utf8_to_win(src_encoding, dest_encoding, src, result, len); + default: + *encodedByteLen = tsql_utf8_to_win(src_encoding, dest_encoding, src, result, len); break; } } @@ -121,22 +122,23 @@ do_encoding_conversion(unsigned char *src, int len, switch (src_encoding) { case PG_BIG5: - *encodedByteLen = big5_to_utf8(src_encoding, dest_encoding, src, result, len); + *encodedByteLen = tsql_big5_to_utf8(src_encoding, dest_encoding, src, result, len); break; case PG_GBK: - *encodedByteLen = gbk_to_utf8(src_encoding, dest_encoding, src, result, len); + *encodedByteLen = tsql_gbk_to_utf8(src_encoding, dest_encoding, src, result, len); break; case PG_UHC: - *encodedByteLen = uhc_to_utf8(src_encoding, dest_encoding, src, result, len); + *encodedByteLen = tsql_uhc_to_utf8(src_encoding, dest_encoding, src, result, len); break; case PG_SJIS: - *encodedByteLen = sjis_to_utf8(src_encoding, dest_encoding, src, result, len); + *encodedByteLen = tsql_sjis_to_utf8(src_encoding, dest_encoding, src, result, len); break; default: - *encodedByteLen = win_to_utf8(src_encoding, dest_encoding, src, result, len); + *encodedByteLen = tsql_win_to_utf8(src_encoding, dest_encoding, src, result, 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..faf6cc5ba7 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: + * tsql_utf8_to_big5: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -17,21 +17,21 @@ * ---------- */ int -utf8_to_big5(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +tsql_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) +tsql_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..5ce8a19390 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: + * tsql_utf8_to_gbk: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -17,21 +17,21 @@ * ---------- */ int -utf8_to_gbk(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +tsql_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) +tsql_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..f15a7afa2b 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: + * tsql_utf8_to_sjis: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -17,21 +17,21 @@ * ---------- */ int -utf8_to_sjis(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +tsql_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) +tsql_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..681dc4e3b5 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: + * tsql_utf8_to_uhc: * src_encoding, -- source encoding id * dest_encoding, -- destination encoding id * src, -- source string (null terminated C string) @@ -17,21 +17,21 @@ * ---------- */ int -utf8_to_uhc(int src_encoding, int dest_encoding, const unsigned char *src, unsigned char *dest, int len) +tsql_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) +tsql_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..a564923e4b 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: + * tsql_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) +tsql_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) +tsql_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..0e3e5a8f0f 100644 --- a/contrib/babelfishpg_common/src/smalldatetime.c +++ b/contrib/babelfishpg_common/src/smalldatetime.c @@ -12,6 +12,7 @@ #include "utils/builtins.h" #include "utils/date.h" #include "utils/datetime.h" +#include "utils/numeric.h" #include "utils/timestamp.h" #include "miscadmin.h" @@ -38,11 +39,19 @@ PG_FUNCTION_INFO_V1(smalldatetime_mi_float8); PG_FUNCTION_INFO_V1(float8_pl_smalldatetime); PG_FUNCTION_INFO_V1(float8_mi_smalldatetime); +PG_FUNCTION_INFO_V1(smalldatetime_to_bit); +PG_FUNCTION_INFO_V1(smalldatetime_to_int2); +PG_FUNCTION_INFO_V1(smalldatetime_to_int4); +PG_FUNCTION_INFO_V1(smalldatetime_to_int8); +PG_FUNCTION_INFO_V1(smalldatetime_to_float4); +PG_FUNCTION_INFO_V1(smalldatetime_to_float8); +PG_FUNCTION_INFO_V1(smalldatetime_to_numeric); + 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 +88,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 +143,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 +154,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 +177,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 +214,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 +262,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 +279,7 @@ timestamptz_smalldatetime(PG_FUNCTION_ARGS) Timestamp result; struct pg_tm tt, - *tm = &tt; + *tm = &tt; fsec_t fsec; int tz; @@ -323,8 +336,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 +377,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 +386,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 +414,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 +427,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 +463,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 +476,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 +487,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 +524,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 +576,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 +608,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 +638,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,17 +659,77 @@ 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; CheckSmalldatetimeRange(result); PG_RETURN_TIMESTAMP(result); } + +Datum +smalldatetime_to_bit(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_BOOL((bool)result); +} + +Datum +smalldatetime_to_int2(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_INT16((int16)round(result)); +} + + +Datum +smalldatetime_to_int4(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_INT32((int32)round(result)); +} + +Datum +smalldatetime_to_int8(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_INT64((int64)round(result)); +} + +Datum +smalldatetime_to_float4(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_FLOAT4((float4)result); +} + +Datum +smalldatetime_to_float8(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_FLOAT8((float8)result); +} + +Datum +smalldatetime_to_numeric(PG_FUNCTION_ARGS) +{ + Timestamp timestamp_left = PG_GETARG_TIMESTAMP(0); + float8 result = calculateDaysFromDefaultDatetime(timestamp_left); + PG_RETURN_NUMERIC(DirectFunctionCall1(float8_numeric, Float8GetDatum(result))); +} \ No newline at end of file diff --git a/contrib/babelfishpg_common/src/sqlvariant.c b/contrib/babelfishpg_common/src/sqlvariant.c index 19f0ba4548..2554a6354a 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", + GUC_CONTEXT_CONFIG, + 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", + GUC_CONTEXT_CONFIG, + 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..4c6519498c 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); + } + + sys_nspoid = get_namespace_oid("sys", true); + + if (!OidIsValid(sys_nspoid)) + PG_RETURN_INT32(0); + + /* mark the hash table initialised */ + inited_ht_oid2typecode = true; - /* 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); + /* 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,48 @@ translate_pg_type_to_tsql(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } -Oid get_type_oid(int type_code) +Oid +get_tsql_datatype_oid(char *type_name) +{ + if(type_name != NULL){ + for (int i = 0; i < TOTAL_TYPECODE_COUNT; i++) + { + if (!strcmp(type_infos[i].tsql_typname, type_name)) { + return type_infos[i].oid; + } + } + } + return InvalidOid; +} + +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_sys_binary_oid = InvalidOid; +Oid tsql_varbinary_oid = InvalidOid; +Oid tsql_sys_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) @@ -336,6 +354,14 @@ is_tsql_binary_datatype(Oid oid) return tsql_binary_oid == oid; } +bool +is_tsql_sys_binary_datatype(Oid oid) +{ + if (tsql_sys_binary_oid == InvalidOid) + tsql_sys_binary_oid = lookup_tsql_datatype_oid("binary"); + return tsql_sys_binary_oid == oid; +} + bool is_tsql_varbinary_datatype(Oid oid) { @@ -344,6 +370,14 @@ is_tsql_varbinary_datatype(Oid oid) return tsql_varbinary_oid == oid; } +bool +is_tsql_sys_varbinary_datatype(Oid oid) +{ + if (tsql_sys_varbinary_oid == InvalidOid) + tsql_sys_varbinary_oid = lookup_tsql_datatype_oid("varbinary"); + return tsql_sys_varbinary_oid == oid; +} + bool is_tsql_rowversion_datatype(Oid oid) { @@ -363,7 +397,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 +437,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 +467,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 +486,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..667b09c301 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); @@ -91,7 +93,9 @@ extern bool is_tsql_text_datatype(Oid oid); extern bool is_tsql_ntext_datatype(Oid oid); extern bool is_tsql_image_datatype(Oid oid); extern bool is_tsql_binary_datatype(Oid oid); +extern bool is_tsql_sys_binary_datatype(Oid oid); extern bool is_tsql_varbinary_datatype(Oid oid); +extern bool is_tsql_sys_varbinary_datatype(Oid oid); extern bool is_tsql_rowversion_datatype(Oid oid); extern bool is_tsql_timestamp_datatype(Oid oid); extern bool is_tsql_rowversion_or_timestamp_datatype(Oid oid); @@ -104,10 +108,11 @@ extern void handle_type_and_collation(struct Node *node, Oid typid, Oid collatio 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); +extern Oid get_tsql_datatype_oid(char *type_name); -/* - * 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..7fade4c93d 100644 --- a/contrib/babelfishpg_common/src/varbinary.c +++ b/contrib/babelfishpg_common/src/varbinary.c @@ -16,7 +16,9 @@ #include "access/hash.h" #include "catalog/pg_collation.h" #include "catalog/pg_type.h" +#include "collation.h" #include "common/int.h" +#include "encoding/encoding.h" #include "lib/hyperloglog.h" #include "libpq/pqformat.h" #include "miscadmin.h" @@ -78,6 +80,7 @@ PG_FUNCTION_INFO_V1(float8binary); PG_FUNCTION_INFO_V1(binaryfloat4); PG_FUNCTION_INFO_V1(binaryfloat8); + /***************************************************************************** * USER I/O ROUTINES * *****************************************************************************/ @@ -131,12 +134,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 +166,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 +327,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 +355,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 +375,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 +397,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 +410,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 +428,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 +513,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 +527,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 +535,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 +543,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 +564,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 +593,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,36 +622,65 @@ 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); /* Source string is UTF-8 */ + char *encoded_data; + 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; + coll_info collInfo; + int encodedByteLen; + MemoryContext ccxt = CurrentMemoryContext; 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 */ + PG_TRY(); + { + collInfo = lookup_collation_table(get_server_collation_oid_internal(false)); + encoded_data = encoding_conv_util(data, len, PG_UTF8, collInfo.enc, &encodedByteLen); + } + PG_CATCH(); + { + MemoryContext ectx; + ErrorData *errorData; + + ectx = MemoryContextSwitchTo(ccxt); + errorData = CopyErrorData(); + FlushErrorState(); + MemoryContextSwitchTo(ectx); + + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Failed to convert from data type varchar to varbinary, %s", + errorData->message))); + } + PG_END_TRY(); + + /* + * If typmod is -1 (or invalid), use the actual length + * Length should be checked after encoding into server encoding + */ if (typmod < (int32) VARHDRSZ) - maxlen = len; + maxlen = encodedByteLen; else maxlen = typmod - VARHDRSZ; - if (len > maxlen) - len = maxlen; + if (encodedByteLen > maxlen) + encodedByteLen = maxlen; - result = (bytea *) palloc(len + VARHDRSZ); - SET_VARSIZE(result, len + VARHDRSZ); + result = (bytea *) palloc(encodedByteLen + VARHDRSZ); + SET_VARSIZE(result, encodedByteLen + VARHDRSZ); rp = VARDATA(result); - memcpy(rp, data, len); + memcpy(rp, encoded_data, encodedByteLen); PG_RETURN_BYTEA_P(result); } @@ -651,25 +688,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,44 +727,85 @@ 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 */ - if (maxlen < 0 || len <= maxlen) - result = (VarChar *) cstring_to_text_with_len(data, len); - /* Else truncate it */ - else - result = (VarChar *) cstring_to_text_with_len(data, maxlen); + bytea *source = PG_GETARG_BYTEA_PP(0); + char *data = VARDATA_ANY(source); /* Source data is server encoded */ + VarChar *result; + char *encoded_result; + size_t len = VARSIZE_ANY_EXHDR(source); + int32 typmod = PG_GETARG_INT32(1); + int32 maxlen = typmod - VARHDRSZ; + coll_info collInfo; + int encodedByteLen; + MemoryContext ccxt = CurrentMemoryContext; + + /* + * Allow trailing null bytes + * Its safe since multi byte UTF-8 does not contain 0x00 + * This is needed since we implicity add trailing zeroes to + * binary type if input is less than binary(n) + * ex: CAST(CAST('a' AS BINARY(10)) AS VARCHAR) should work + * and not fail because of null byte + */ + while(len>0 && data[len-1] == '\0') + len -= 1; + + /* + * Cast the entire input binary data if maxlen is + * invalid or supplied data fits it + * Else truncate it + */ + PG_TRY(); + { + collInfo = lookup_collation_table(get_server_collation_oid_internal(false)); + if (maxlen < 0 || len <= maxlen) + encoded_result = encoding_conv_util(data, len, collInfo.enc, PG_UTF8, &encodedByteLen); + else + encoded_result = encoding_conv_util(data, maxlen, collInfo.enc, PG_UTF8, &encodedByteLen); + } + PG_CATCH(); + { + MemoryContext ectx; + ErrorData *errorData; + + ectx = MemoryContextSwitchTo(ccxt); + errorData = CopyErrorData(); + FlushErrorState(); + MemoryContextSwitchTo(ectx); + + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Failed to convert from data type varbinary to varchar, %s", + errorData->message))); + } + PG_END_TRY(); + + result = (VarChar *) cstring_to_text_with_len(encoded_result, encodedByteLen); + PG_RETURN_VARCHAR_P(result); } 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 +826,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 +865,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 +894,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 +923,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 +944,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 +952,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 +973,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 +981,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 +1002,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 +1010,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 +1026,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 +1042,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 +1058,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 +1079,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 +1087,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 +1108,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 +1116,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 +1132,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 +1148,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 +1167,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 +1178,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 +1198,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 +1209,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 +1229,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 +1240,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 +1258,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 +1276,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 +1294,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 +1318,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 +1342,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 +1366,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 +1386,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 +1397,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 +1417,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 +1428,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 +1452,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) +int4varbinary_div(PG_FUNCTION_ARGS) { - bytea *source1 = PG_GETARG_BYTEA_PP(0); - bytea *source2 = PG_GETARG_BYTEA_PP(1); + int32 dividend = PG_GETARG_INT32(0); + bytea *varbinary_divisor = PG_GETARG_BYTEA_PP(1); + char *data = VARDATA_ANY(varbinary_divisor); + int32 len; + int32 result_len; + int32 *resultint = palloc0(sizeof(int32)); + int32 divisor = 0; + int32 result; + len = VARSIZE_ANY_EXHDR(varbinary_divisor); + result_len = len > sizeof(int32) ? sizeof(int32) : len; + memcpy((char *) resultint + (sizeof(int32)- result_len), data, result_len); + + divisor = pg_ntoh32((int32) *resultint); + if (divisor == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + result = dividend / divisor; + PG_RETURN_INT32(result); +} + +Datum +varbinaryint4_div(PG_FUNCTION_ARGS) +{ + bytea *varbinary_dividend = PG_GETARG_BYTEA_PP(0); + int32 divisor = PG_GETARG_INT32(1); + char *data = VARDATA_ANY(varbinary_dividend); + int32 len; + int32 result_len; + int32 *resultint = palloc0(sizeof(int32)); + int32 dividend = 0; + int32 result; + + len = VARSIZE_ANY_EXHDR(varbinary_dividend); + result_len = len > sizeof(int32) ? sizeof(int32) : len; + memcpy((char *) resultint + (sizeof(int32)- result_len), data, result_len); + dividend = pg_ntoh32((int32) *resultint); + + if (divisor == 0) + { + ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + /* ensure compiler realizes we mustn't reach the division (gcc bug) */ + PG_RETURN_NULL(); + } + + result = dividend / divisor; + PG_RETURN_INT32(result); + +} + + +Datum +varbinary_cmp(PG_FUNCTION_ARGS) +{ + bytea *source1 = PG_GETARG_BYTEA_PP(0); + bytea *source2 = PG_GETARG_BYTEA_PP(1); + PG_RETURN_INT32(varbinarycompare(source1, source2)); } @@ -1479,9 +1649,11 @@ 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..a4ccfd571c 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 (;;) { @@ -92,7 +92,7 @@ is_basetype_nchar_nvarchar(Oid typid) * GetUTF8CodePoint - extract the next Unicode code point from 1..4 * bytes at 'in' in UTF-8 encoding. */ -static inline int32_t +int32_t GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p) { int32_t code; @@ -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..9be7a75f1a 100644 --- a/contrib/babelfishpg_common/src/varchar.h +++ b/contrib/babelfishpg_common/src/varchar.h @@ -3,7 +3,8 @@ #include "postgres.h" +extern int32_t GetUTF8CodePoint(const unsigned char *in, int len, int *consumed_p); 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/Makefile b/contrib/babelfishpg_money/Makefile index 1747e0f0da..673d4cc0f4 100755 --- a/contrib/babelfishpg_money/Makefile +++ b/contrib/babelfishpg_money/Makefile @@ -11,7 +11,7 @@ DATA_built = babelfishpg_money--1.1.0.sql #include ../Makefile.common CFLAGS = `$(PG_CONFIG) --includedir-server` -PG_CFLAGS += -Werror +PG_CFLAGS += -Werror -Wfloat-conversion PG_CFLAGS += -fstack-protector-strong TESTS = $(wildcard test/sql/*.sql) diff --git a/contrib/babelfishpg_money/fixeddecimal.c b/contrib/babelfishpg_money/fixeddecimal.c index 14fc29b1ba..a07c64a743 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)); } @@ -2966,6 +2981,9 @@ fixeddecimalaggstateserialize(PG_FUNCTION_ARGS) if (!AggCheckCallContext(fcinfo, NULL)) elog(ERROR, "aggregate function called in non-aggregate context"); + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + state = (FixedDecimalAggState *) PG_GETARG_POINTER(0); pq_begintypsend(&buf); @@ -2991,6 +3009,9 @@ fixeddecimalaggstatedeserialize(PG_FUNCTION_ARGS) if (!AggCheckCallContext(fcinfo, NULL)) elog(ERROR, "aggregate function called in non-aggregate context"); + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + sstate = PG_GETARG_BYTEA_P(0); /* @@ -3034,7 +3055,7 @@ fixeddecimalaggstatecombine(PG_FUNCTION_ARGS) if (collectstate == NULL) { collectstate = (FixedDecimalAggState *) palloc(sizeof - (FixedDecimalAggState)); + (FixedDecimalAggState)); collectstate->sumX = 0; collectstate->N = 0; } @@ -3046,9 +3067,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/Makefile b/contrib/babelfishpg_tds/Makefile index 189fc8433d..d734bfd296 100644 --- a/contrib/babelfishpg_tds/Makefile +++ b/contrib/babelfishpg_tds/Makefile @@ -9,7 +9,7 @@ tds_backend = $(tds_top_dir)/src/backend tds_include = $(tds_top_dir)/src/include TSQL_SRC = ../babelfishpg_tsql -PG_CFLAGS += -Werror +PG_CFLAGS += -Werror -Wfloat-conversion PG_CFLAGS += -fstack-protector-strong PG_CPPFLAGS += -I$(TSQL_SRC) -I$(PG_SRC) -I$(tds_top_dir) -DFAULT_INJECTOR diff --git a/contrib/babelfishpg_tds/error_mapping.txt b/contrib/babelfishpg_tds/error_mapping.txt index bf94956fc0..6f6f6ee4ca 100644 --- a/contrib/babelfishpg_tds/error_mapping.txt +++ b/contrib/babelfishpg_tds/error_mapping.txt @@ -52,6 +52,7 @@ P0001 ERRCODE_RAISE_EXCEPTION "%s" SQL_ERROR_9809 16 "is not supported for conve 25P01 ERRCODE_NO_ACTIVE_SQL_TRANSACTION "%s can only be used in transaction blocks" SQL_ERROR_628 16 "SAVEPOINT" 25P01 ERRCODE_NO_ACTIVE_SQL_TRANSACTION "%s can only be used in transaction blocks" SQL_ERROR_3903 16 "ROLLBACK TO SAVEPOINT" 25001 ERRCODE_ACTIVE_SQL_TRANSACTION "%s cannot run inside a transaction block" SQL_ERROR_574 16 +25001 ERRCODE_ACTIVE_SQL_TRANSACTION "%s command cannot be used inside user transactions." SQL_ERROR_6615 16 42809 ERRCODE_WRONG_OBJECT_TYPE "\"%s\" is not a table or materialized view" SQL_ERROR_10610 16 42809 ERRCODE_WRONG_OBJECT_TYPE "cannot create index on relation \"%s\"" SQL_ERROR_10610 16 42809 ERRCODE_WRONG_OBJECT_TYPE "%s parameter should be of %s type" SQL_ERROR_16902 16 @@ -176,3 +177,9 @@ XX000 ERRCODE_INTERNAL_ERROR "The table-valued parameter \"%s\" must be declared 42P01 ERRCODE_UNDEFINED_TABLE "table \"%s\" does not exist" SQL_ERROR_3701 16 42P13 ERRCODE_INVALID_FUNCTION_DEFINITION "PL/tsql functions cannot return type %s" SQL_ERROR_2733 16 0A000 ERRCODE_FEATURE_NOT_SUPPORTED "Column name or number of supplied values does not match table definition." SQL_ERROR_213 16 +42501 ERRCODE_INSUFFICIENT_PRIVILEGE "Only members of the sysadmin role can execute this stored procedure." SQL_ERROR_15003 16 +42809 ERRCODE_WRONG_OBJECT_TYPE "The target \"%s\" of the OUTPUT INTO clause cannot be a view or common table expression." SQL_ERROR_330 16 +22008 ERRCODE_DATETIME_VALUE_OUT_OF_RANGE "The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart" SQL_ERROR_535 16 +22023 ERRCODE_INVALID_PARAMETER_VALUE "\'%s\' is not a recognized %s option" SQL_ERROR_155 15 +22023 ERRCODE_INVALID_PARAMETER_VALUE "The datepart %s is not supported by date function %s for data type %s." SQL_ERROR_9810 16 +22008 ERRCODE_DATETIME_VALUE_OUT_OF_RANGE "Adding a value to a \'%s\' column caused an overflow." SQL_ERROR_517 16 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..29165031c7 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; @@ -187,14 +193,20 @@ 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()) + { + HOLD_INTERRUPTS(); + 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); + RESUME_INTERRUPTS(); + } return false; } else { - bool flag = false; + bool flag = false; error_map_node *tmp = map_info->head; while (tmp) @@ -210,17 +222,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 +260,23 @@ 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); + /* Possible infinite loop of errors. Do not touch it further. */ + if (!error_stack_full()) + { + HOLD_INTERRUPTS(); + 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); + RESUME_INTERRUPTS(); + } *tsql_error_code = ERRCODE_PLTSQL_ERROR_NOT_MAPPED; *tsql_error_severity = 16; @@ -264,7 +289,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 @@ -281,7 +309,9 @@ emit_tds_log(ErrorData *edata) if (edata->elevel < ERROR) { + HOLD_INTERRUPTS(); elog(DEBUG5, "suppressing informational client message < ERROR"); + RESUME_INTERRUPTS(); /* reset the flag */ tds_disable_error_log_hook = false; @@ -291,8 +321,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 +345,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,10 +364,13 @@ emit_tds_log(ErrorData *edata) PG_CATCH(); { /* Log the internal error message */ - ErrorData *next_edata; + ErrorData *next_edata; + + HOLD_INTERRUPTS(); next_edata = CopyErrorData(); elog(LOG, "internal error occurred: %s", next_edata->message); FreeErrorData(next_edata); + RESUME_INTERRUPTS(); } PG_END_TRY(); @@ -360,6 +394,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..7875ec231d 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,86 @@ TdsGucDefaultPacketSizeCheck(int *newvalue, void **extra, GucSource source) return true; } -static bool +static void +set_newval_to_product_version(char **newval) +{ + free(*newval); + *newval = strdup(product_version); + if (*newval == NULL) + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); +} + +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 \'.\' "))); - *newval = product_version; + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter 4 valid numbers separated by \'.\' "))); + set_newval_to_product_version(newval); 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"))); - *newval = product_version; + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid major version number between 11 and 16"))); + set_newval_to_product_version(newval); 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"))); - *newval = product_version; + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid minor version number between 0 and 255"))); + set_newval_to_product_version(newval); 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"))); - *newval = product_version; + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter a valid micro version number between 0 and 65535"))); + set_newval_to_product_version(newval); 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 \'.\' "))); - *newval = product_version; + (errmsg("babelfishpg_tds.product_version cannot be set. Please enter 4 valid numbers separated by \'.\' "))); + set_newval_to_product_version(newval); return true; } - return true; + return true; } /* @@ -190,198 +203,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 a5e0343bd6..88dd101794 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; @@ -82,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; @@ -98,24 +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_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; @@ -125,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 @@ -144,18 +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; -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; @@ -167,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 */ @@ -182,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 @@ -199,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(); @@ -265,15 +269,22 @@ TdsLanguageBufferSize() return mul_size(LANGDATALEN, NumBackendStatSlots); } +static Size +TdsContextInfoBufferSize() +{ + return mul_size(CONTEXTINFOLEN, NumBackendStatSlots); +} + static Size tds_memsize() { - Size size; + Size size; size = TdsStatusArraySize(); size = add_size(size, TdsLibraryNameBufferSize()); size = add_size(size, TdsHostNameBufferSize()); size = add_size(size, TdsLanguageBufferSize()); + size = add_size(size, TdsContextInfoBufferSize()); return size; } @@ -298,7 +309,7 @@ tds_shmem_request() static void tds_status_shmem_startup(void) { - bool found; + bool found; char *buffer; /* @@ -307,8 +318,8 @@ tds_status_shmem_startup(void) LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); TdsStatusArray = (TdsStatus *) ShmemInitStruct("TDS Status Array", - TdsStatusArraySize(), - &found); + TdsStatusArraySize(), + &found); if (!found) { /* @@ -325,7 +336,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsLibraryNameBuffer, 0, TdsLibraryNameBufferSize()); @@ -344,7 +355,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsHostNameBuffer, 0, TdsHostNameBufferSize()); @@ -363,7 +374,7 @@ tds_status_shmem_startup(void) if (!found) { - int i; + int i; MemSet(TdsLanguageBuffer, 0, TdsLanguageBufferSize()); @@ -376,9 +387,29 @@ 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 + /* + * If we're in the postmaster (or a standalone backend...), set up a shmem * exit hook to persist the dirty outlines */ if (!IsUnderPostmaster) @@ -430,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. @@ -510,6 +541,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; @@ -532,7 +565,7 @@ tdsstat_bestart(void) } static LocalTdsStatus * -tdsstat_fetch_stat_local_tdsentry (int beid) +tdsstat_fetch_stat_local_tdsentry(int beid) { LocalTdsStatus *localentry; @@ -562,7 +595,7 @@ tdsstat_read_current_status(void) volatile TdsStatus *tdsentry; LocalTdsStatus *localtable; LocalTdsStatus *localentry; - int i; + int i; if (isLocalStatusTableValid) return; /* already done */ @@ -606,13 +639,16 @@ 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; 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; @@ -701,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); @@ -725,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; @@ -750,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; @@ -787,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 */ @@ -797,10 +831,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; } @@ -809,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); @@ -868,6 +913,7 @@ void TdsSetDatabaseStatVariable(int16 db_id) { volatile TdsStatus *vtdsentry = MyTdsStatusEntry; + PGSTAT_BEGIN_WRITE_ACTIVITY(vtdsentry); vtdsentry->database_id = db_id; @@ -882,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); @@ -891,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); @@ -916,8 +962,44 @@ invalidate_stat_table(void) isLocalStatusTableValid = false; } -char* +char * get_tds_host_name(void) { return MyTdsHostName; } + +uint32_t +get_tds_client_pid(void) +{ + return MyTdsClientPid; +} + +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_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 34e19f8c6c..603ddd105d 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) @@ -196,6 +195,9 @@ 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_client_pid = &get_tds_client_pid; + 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; @@ -218,19 +220,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)); @@ -317,7 +319,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. @@ -334,7 +336,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()); @@ -344,7 +346,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; } @@ -353,10 +355,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); @@ -398,7 +399,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; @@ -416,7 +417,7 @@ pe_read_command(StringInfo inBuf) static int pe_process_command() { - int result; + int result; /* Push the error context */ tdserrcontext.callback = TdsErrorContextCallback; @@ -425,12 +426,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..194ed67af2 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); -static void FetchMoreBcpData(StringInfo *message, int dataLenToRead); +void ProcessBCPRequest(TDSRequest request); +static void FetchMoreBcpData(StringInfo *message, int dataLenToRead, bool freeMessageData); 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 @@ -70,12 +70,26 @@ do \ temp->rowCount, colNum + 1, temp->colMetaData[i].columnTdsType))); \ } while(0) -/* Check if Message has enough data to read, if not then fetch more. */ -#define CheckMessageHasEnoughBytesToRead(message, dataLen) \ +/* + * Check if Message has enough data to read column metadata. + * If not then fetch more. + */ +#define CheckMessageHasEnoughBytesToReadColMetadata(message, dataLen) \ +do \ +{ \ + if ((*message)->len - offset < dataLen) \ + FetchMoreBcpData(message, dataLen, false); \ +} while(0) + +/* + * Check if Message has enough data to read the rows' data. + * If not then fetch more. + */ +#define CheckMessageHasEnoughBytesToReadRows(message, dataLen) \ do \ { \ if ((*message)->len - offset < dataLen) \ - FetchMoreBcpData(message, dataLen); \ + FetchMoreBcpData(message, dataLen, true); \ } while(0) /* Check if Message has enough data to read, if not then fetch more. */ @@ -87,42 +101,53 @@ do \ } while(0) static void -FetchMoreBcpData(StringInfo *message, int dataLenToRead) +FetchMoreBcpData(StringInfo *message, int dataLenToRead, bool freeMessageData) { - 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); + /* + * If we are trying to read next packet and freeMessageData is true then + * afford to free it. + * NOTE: We should free the message data only while reading + * rows' data and on the other hand we should not free the + * column-metadata information until we are done with it. + */ + if (freeMessageData) + { + temp = makeStringInfo(); + appendBinaryStringInfo(temp, (*message)->data + offset, (*message)->len - offset); - if ((*message)->data) - pfree((*message)->data); - pfree((*message)); + if ((*message)->data) + pfree((*message)->data); + pfree((*message)); + offset = 0; + } + else + temp = *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) + while (dataLenToRead + offset > 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,12 +161,11 @@ 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; } } - offset = 0; (*message) = temp; } @@ -152,32 +176,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 +211,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 +225,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++; @@ -232,7 +254,7 @@ GetBulkLoadRequest(StringInfo message) for (int currentColumn = 0; currentColumn < colCount; currentColumn++) { - CheckMessageHasEnoughBytesToRead(&message, COLUMNMETADATA_HEADER_LEN); + CheckMessageHasEnoughBytesToReadColMetadata(&message, COLUMNMETADATA_HEADER_LEN); /* UserType */ memcpy(&colmetadata[currentColumn].userType, &message->data[offset], sizeof(uint32_t)); offset += sizeof(uint32_t); @@ -245,7 +267,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: @@ -253,209 +275,213 @@ GetBulkLoadRequest(StringInfo message) case TDS_TYPE_MONEYN: case TDS_TYPE_DATETIMEN: case TDS_TYPE_UNIQUEIDENTIFIER: - CheckMessageHasEnoughBytesToRead(&message, FIXED_LEN_TYPE_COLUMNMETADATA_LEN); + CheckMessageHasEnoughBytesToReadColMetadata(&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++]; + CheckMessageHasEnoughBytesToReadColMetadata(&message, NUMERIC_COLUMNMETADATA_LEN); + 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); + CheckMessageHasEnoughBytesToReadColMetadata(&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); + CheckMessageHasEnoughBytesToReadColMetadata(&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) + { + CheckMessageHasEnoughBytesToReadColMetadata(&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); + } + + CheckMessageHasEnoughBytesToReadColMetadata(&message, sizeof(uint16_t)); + memcpy(&tableLen, &message->data[offset], sizeof(uint16_t)); + offset += sizeof(uint16_t); + + /* Skip table name for now. */ + CheckMessageHasEnoughBytesToReadColMetadata(&message, tableLen * 2); + offset += tableLen * 2; + } + break; case TDS_TYPE_XML: - { - CheckMessageHasEnoughBytesToRead(&message, 1); - colmetadata[currentColumn].maxLen = message->data[offset++]; - } - break; + { + CheckMessageHasEnoughBytesToReadColMetadata(&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; + { + CheckMessageHasEnoughBytesToReadColMetadata(&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; + { + CheckMessageHasEnoughBytesToReadColMetadata(&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; + { + CheckMessageHasEnoughBytesToReadColMetadata(&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; + + CheckMessageHasEnoughBytesToReadColMetadata(&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); + CheckMessageHasEnoughBytesToReadColMetadata(&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 */ - CheckMessageHasEnoughBytesToRead(&message, sizeof(uint8_t)); + CheckMessageHasEnoughBytesToReadColMetadata(&message, sizeof(uint8_t)); 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); + CheckMessageHasEnoughBytesToReadColMetadata(&message, colmetadata[currentColumn].colNameLen * 2); + 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,34 +493,36 @@ 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; - CheckMessageHasEnoughBytesToRead(&message, 1); + CheckMessageHasEnoughBytesToReadRows(&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 +534,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; - } - else - { - CheckMessageHasEnoughBytesToRead(&message, 1); - len = message->data[offset++]; - request->currentBatchSize++; - - if (len == 0) /* null */ + if (colmetadata[i].variantType) { - rowData->isNull[i] = true; - i++; - continue; + len = colmetadata[i].maxLen; } - } - CheckForInvalidLength(len, request, i); + else + { + CheckMessageHasEnoughBytesToReadRows(&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); + CheckMessageHasEnoughBytesToReadRows(&message, len); - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; + /* 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; - } + /* + * 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; - } - break; + 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))); - - CheckMessageHasEnoughBytesToRead(&message, 1); - - len = message->data[offset++]; - request->currentBatchSize++; - if (len == 0) /* null */ { - rowData->isNull[i] = true; - i++; - continue; - } + 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))); - CheckForInvalidLength(len, request, i); + CheckMessageHasEnoughBytesToReadRows(&message, 1); + + len = message->data[offset++]; + request->currentBatchSize++; + if (len == 0) /* null */ + { + rowData->isNull[i] = true; + i++; + continue; + } - CheckMessageHasEnoughBytesToRead(&message, len); + CheckForInvalidLength(len, request, i); - /* Build temp Stringinfo. */ - temp->data = &message->data[offset]; - temp->len = len; - temp->maxlen = colmetadata[i].maxLen; - temp->cursor = 0; + CheckMessageHasEnoughBytesToReadRows(&message, len); - /* Create and store the appropriate datum for this column. */ - rowData->columnValues[i] = TdsTypeNumericToDatum(temp, colmetadata[i].scale); + /* Build temp Stringinfo. */ + temp->data = &message->data[offset]; + temp->len = len; + temp->maxlen = colmetadata[i].maxLen; + temp->cursor = 0; - offset += len; - request->currentBatchSize += len; - } - break; + /* + * Create and store the appropriate datum for this + * column. + */ + rowData->columnValues[i] = TdsTypeNumericToDatum(temp, colmetadata[i].scale); + + offset += len; + request->currentBatchSize += len; + } + break; case TDS_TYPE_CHAR: case TDS_TYPE_VARCHAR: @@ -623,219 +657,241 @@ 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) { - CheckForInvalidLength(len, request, i); + CheckMessageHasEnoughBytesToReadRows(&message, sizeof(short)); + memcpy(&len, &message->data[offset], sizeof(short)); + offset += sizeof(short); + request->currentBatchSize += sizeof(short); + if (len != 0xffff) + { + CheckForInvalidLength(len, request, i); + + CheckMessageHasEnoughBytesToReadRows(&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 + { + 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; + + CheckMessageHasEnoughBytesToReadRows(&message, 1); - offset += len; - request->currentBatchSize += len; + /* + * 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 */ + + CheckMessageHasEnoughBytesToReadRows(&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); + + CheckMessageHasEnoughBytesToReadRows(&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; - } + CheckMessageHasEnoughBytesToReadRows(&message, sizeof(uint32_t)); - CheckForInvalidLength(len, request, i); + memcpy(&len, &message->data[offset], sizeof(uint32_t)); + offset += sizeof(uint32_t); + request->currentBatchSize += sizeof(uint32_t); - CheckMessageHasEnoughBytesToRead(&message, len); - - /* 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)); + CheckMessageHasEnoughBytesToReadRows(&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++; } request->rowData = lappend(request->rowData, rowData); - CheckMessageHasEnoughBytesToRead(&message, 1); + CheckMessageHasEnoughBytesToReadRows(&message, 1); } /* - * 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); - + CheckMessageHasEnoughBytesToReadRows(&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 +905,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 +926,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 +947,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 +964,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 +978,25 @@ 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(); + HOLD_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,9 +1012,10 @@ 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))); + RESUME_INTERRUPTS(); PG_RE_THROW(); } PG_END_TRY(); @@ -964,12 +1029,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 +1045,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 +1060,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 +1080,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 +1126,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..d5ea9eebbc 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,350 +410,458 @@ 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; + return var->vartypmod; } - else if (typmod1 == -1) - { - precision1 = precision2; - scale1 = scale2; - } - 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; + } + + /* + * 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; } + /* - * Control reaching here for only arithmetic overflow cases + * 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); + /* + * 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; - } + 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); + } + + pfree(aggFuncName); + return ((precision << 16) | scale) + VARHDRSZ; + } + case T_PlaceHolderVar: + { + PlaceHolderVar *phv = (PlaceHolderVar *) expr; + + return resolve_numeric_typmod_from_exp((Node *) phv->phexpr); + } + case T_RelabelType: { - precision = tds_default_numeric_precision; - scale = Max(scale, 6); + 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 */ + default: + return -1; + } +} - pfree(aggFuncName); - return ((precision << 16) | scale) + VARHDRSZ; - } - case T_PlaceHolderVar: +/* 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: { - PlaceHolderVar *phv = (PlaceHolderVar *) expr; + /* + * 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 resolve_numeric_typmod_from_exp((Node *) phv->phexpr); + return VARSIZE_ANY(source); + } + else + return -1; } - case T_RelabelType: + case T_FuncExpr: { - RelabelType *rlt = (RelabelType *) expr; + 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 (rlt->resulttypmod != -1) - return rlt->resulttypmod; - else - return resolve_numeric_typmod_from_exp((Node *) rlt->arg); + 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: @@ -786,13 +896,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 +922,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 +960,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 +968,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 +976,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 +999,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 +1019,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 +1055,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 +1072,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 +1096,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 +1122,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 +1135,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 +1152,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 +1184,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 +1197,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 +1219,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 +1240,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 +1252,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 +1278,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 +1287,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 +1321,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 +1332,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 +1345,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 +1372,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 +1407,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 +1416,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 +1452,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 +1512,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 +1527,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 +1559,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 +1608,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 +1659,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 +1674,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 +1705,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 +1724,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 +1742,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,24 +1765,24 @@ 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 */ - 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; @@ -1654,20 +1791,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 +1814,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 +1841,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 +1854,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 +1870,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 +1885,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 +1909,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 +1923,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 +1949,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 +1990,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 +2047,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 +2071,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 +2085,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 +2096,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 +2111,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 +2150,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 +2160,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 +2180,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 +2242,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 +2271,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 +2285,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 +2328,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 +2360,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 +2387,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 +2409,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 +2445,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 +2483,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 +2500,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 +2512,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 +2541,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 +2577,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 +2590,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 +2602,71 @@ 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_XML: + /* + * To send NULL,we have to + * indicate it using 0xffffffffffffffff + * (PLP_NULL) + */ + simpleRowSize += 8; + 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; } @@ -2478,7 +2674,7 @@ TdsPrintTup(TupleTableSlot *slot, DestReceiver *self) } } - if (nullMapSize < simpleRowSize) + if (nullMapSize <= simpleRowSize) { rowToken = TDS_TOKEN_NBCROW; } @@ -2488,7 +2684,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 +2706,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 +2724,69 @@ 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_XML: + + /* + * In case of TDS version lower than or equal to 7.3A, + * we need to send 0xffffffffffffffff (PLP_NULL) + */ + TdsPutUInt64LE(0xffffffffffffffff); + 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 +2809,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 +2818,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 +2850,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 +2876,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 +2892,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 +2923,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 +2938,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 +2952,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 +2976,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 +2992,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 +3034,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 +3055,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 +3094,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 +3111,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 +3148,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 +3182,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 +3191,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 +3200,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 +3221,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 +3244,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 +3286,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 +3300,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 +3309,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 c990c63349..68033b36a9 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,20 @@ 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; + tvp_lookup_list = NIL; 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 +514,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 +533,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) @@ -541,6 +551,7 @@ SPExecuteSQL(TDSRequestSP req) } PG_CATCH(); { + HOLD_INTERRUPTS(); if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) ereport(LOG, (errmsg("sp_executesql statement: %s", s.data), @@ -548,6 +559,8 @@ SPExecuteSQL(TDSRequestSP req) errdetail_params(req->nTotalParams))); TDSStatementExceptionCallback(NULL, NULL, false); + RESUME_INTERRUPTS(); + tvp_lookup_list = NIL; PG_RE_THROW(); } PG_END_TRY(); @@ -572,12 +585,24 @@ SPExecuteSQL(TDSRequestSP req) { ErrorContextCallback *plerrcontext = error_context_stack; + error_context_stack = plerrcontext->previous; - ereport(LOG, - (errmsg("sp_executesql statement: %s", s.data), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + /* In certain cases TVP can throw error for errdetail_params. */ + PG_TRY(); + { + ereport(LOG, + (errmsg("sp_executesql statement: %s", s.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + } + PG_CATCH(); + { + ereport(LOG, + (errmsg("sp_executesql statement: %s", s.data), + errhidestmt(true))); + } + PG_END_TRY(); pltsql_plugin_handler_ptr->stmt_needs_logging = false; error_context_stack = plerrcontext; @@ -588,6 +613,7 @@ SPExecuteSQL(TDSRequestSP req) */ TDSLogDuration(s.data); pfree(codeblock); + tvp_lookup_list = NIL; } static void @@ -596,10 +622,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 +633,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 +665,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 +710,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 +725,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 +750,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. */ @@ -735,6 +765,7 @@ SPExecute(TDSRequestSP req) } PG_CATCH(); { + HOLD_INTERRUPTS(); if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) ereport(LOG, (errmsg("sp_execute handle: %d", req->handle), @@ -743,6 +774,7 @@ SPExecute(TDSRequestSP req) TDSStatementExceptionCallback(NULL, NULL, false); tvp_lookup_list = NIL; + RESUME_INTERRUPTS(); PG_RE_THROW(); } PG_END_TRY(); @@ -766,12 +798,25 @@ 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, - (errmsg("sp_execute handle: %d", req->handle), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + /* In certain cases TVP can throw error for errdetail_params. */ + PG_TRY(); + { + ereport(LOG, + (errmsg("sp_execute handle: %d", req->handle), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + } + PG_CATCH(); + { + ereport(LOG, + (errmsg("sp_execute handle: %d", req->handle), + errhidestmt(true))); + } + PG_END_TRY(); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; error_context_stack = plerrcontext; } @@ -790,24 +835,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 +865,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 +876,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) @@ -853,15 +901,17 @@ SPPrepExec(TDSRequestSP req) } PG_CATCH(); { + HOLD_INTERRUPTS(); 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))); TDSStatementExceptionCallback(NULL, NULL, false); tvp_lookup_list = NIL; + RESUME_INTERRUPTS(); PG_RE_THROW(); } PG_END_TRY(); @@ -891,11 +941,25 @@ SPPrepExec(TDSRequestSP req) ErrorContextCallback *plerrcontext = error_context_stack; error_context_stack = plerrcontext->previous; - ereport(LOG, - (errmsg("sp_prepexec handle: %d, " - "statement: %s", req->handle, s.data), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + + /* In certain cases TVP can throw error for errdetail_params. */ + PG_TRY(); + { + ereport(LOG, + (errmsg("sp_prepexec handle: %d, " + "statement: %s", req->handle, s.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + } + PG_CATCH(); + { + ereport(LOG, + (errmsg("sp_prepexec handle: %d, " + "statement: %s", req->handle, s.data), + errhidestmt(true))); + } + PG_END_TRY(); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; error_context_stack = plerrcontext; } @@ -916,20 +980,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 +1010,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 +1044,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 +1061,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,19 +1085,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); @@ -1046,7 +1111,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; @@ -1062,14 +1127,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) @@ -1077,6 +1145,7 @@ SPCustomType(TDSRequestSP req) } PG_CATCH(); { + HOLD_INTERRUPTS(); if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) ereport(LOG, (errmsg("stored procedure: %s", req->name.data), @@ -1085,6 +1154,7 @@ SPCustomType(TDSRequestSP req) tvp_lookup_list = NIL; + RESUME_INTERRUPTS(); PG_RE_THROW(); } PG_END_TRY(); @@ -1120,11 +1190,25 @@ 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), - errhidestmt(true), - errdetail_params(req->nTotalParams))); + + /* In certain cases TVP can throw error for errdetail_params. */ + PG_TRY(); + { + ereport(LOG, + (errmsg("stored procedure: %s", req->name.data), + errhidestmt(true), + errdetail_params(req->nTotalParams))); + } + PG_CATCH(); + { + ereport(LOG, + (errmsg("stored procedure: %s", req->name.data), + errhidestmt(true))); + } + PG_END_TRY(); + pltsql_plugin_handler_ptr->stmt_needs_logging = false; error_context_stack = plerrcontext; } @@ -1134,6 +1218,7 @@ SPCustomType(TDSRequestSP req) */ TDSLogDuration(req->name.data); pfree(codeblock); + tvp_lookup_list = NIL; } static void @@ -1142,7 +1227,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); @@ -1160,7 +1246,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. */ @@ -1186,18 +1272,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; @@ -1209,7 +1295,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); /* @@ -1217,13 +1306,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; @@ -1231,17 +1320,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)); @@ -1251,7 +1340,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); /* @@ -1259,13 +1351,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; @@ -1275,12 +1367,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; @@ -1294,11 +1387,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 */ @@ -1342,7 +1435,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; @@ -1353,28 +1446,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; } @@ -1383,8 +1480,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)); @@ -1392,7 +1489,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; @@ -1403,20 +1501,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++]; @@ -1428,363 +1528,344 @@ 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; - } + /* 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); - 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))); + memcpy(&temp->len, &message->data[offset], sizeof(temp->len)); - /* - * 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; - - /* - * 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); - /* 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) @@ -1797,11 +1878,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; @@ -1814,7 +1896,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: @@ -1841,8 +1923,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; @@ -1869,7 +1951,7 @@ GetSPCursorHandleParameter(TDSRequestSP request) static void GetSPCursorPreparedHandleParameter(TDSRequestSP request) { - switch(request->spType) + switch (request->spType) { case SP_CURSORPREPEXEC: case SP_CURSOROPEN: @@ -1921,7 +2003,7 @@ GetSPCursorPreparedHandleParameter(TDSRequestSP request) static void GetSPHandleParameter(TDSRequestSP request) { - switch(request->spType) + switch (request->spType) { case SP_CURSORPREPARE: case SP_CURSORPREPEXEC: @@ -1984,8 +2066,8 @@ FillStoredProcedureCallFromParameterToken(TDSRequestSP req, StringInfo inBuf) { int paramno; int numParams; - ParameterToken token = NULL; - StringInfo name; + ParameterToken token = NULL; + StringInfo name; Assert(req->queryParameter == NULL); @@ -2008,7 +2090,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++; @@ -2023,7 +2105,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++; } @@ -2050,9 +2132,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; @@ -2061,7 +2143,7 @@ InitializeDataParamTokenIndex(TDSRequestSP request) { request->nTotalParams++; - if ((token->flags & 0x01) == 1) + if ((token->flags & 0x01) == 1) request->nOutParams++; } @@ -2076,7 +2158,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++; } @@ -2087,7 +2169,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) @@ -2097,7 +2179,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); } } @@ -2167,16 +2250,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; @@ -2203,21 +2286,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) { @@ -2237,26 +2320,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) @@ -2268,35 +2352,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, @@ -2311,8 +2396,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"; @@ -2327,49 +2412,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) @@ -2404,7 +2491,7 @@ HandleSPCursorOpenCommon(TDSRequestSP req) static void GenerateBindParamsData(TDSRequestSP req) { - uint16_t count = 0; + uint16_t count = 0; ParameterToken tempBindParam; bool isNull; TdsIoFunctionInfo tempFuncInfo; @@ -2441,7 +2528,7 @@ GenerateBindParamsData(TDSRequestSP req) { tempFuncInfo = TdsLookupTypeFunctionsByTdsId(tempBindParam->type, - tempBindParam->maxLen); + tempBindParam->maxLen); isNull = tempBindParam->isNull; ptype = tempBindParam->paramMeta.pgTypeOid; @@ -2464,7 +2551,7 @@ static void FetchAndValidateCursorFetchOptions(TDSRequestSP req, int *fetchType, int *rownum, int *howMany) { - ParameterToken token; + ParameterToken token; token = req->cursorExtraArg1; Assert(token); @@ -2475,7 +2562,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: @@ -2483,24 +2570,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; @@ -2514,9 +2603,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 && @@ -2563,11 +2652,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); @@ -2579,7 +2668,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) @@ -2612,8 +2701,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); @@ -2623,7 +2712,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) @@ -2654,8 +2743,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); @@ -2665,7 +2754,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) @@ -2688,7 +2777,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); } @@ -2696,12 +2785,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); @@ -2731,7 +2821,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) @@ -2762,12 +2852,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++) @@ -2799,13 +2889,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) @@ -2836,29 +2926,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; @@ -2871,18 +2963,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) { @@ -2903,15 +2994,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 */ @@ -2921,39 +3012,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; @@ -2968,8 +3058,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; } } @@ -2983,29 +3073,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) @@ -3034,53 +3123,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) @@ -3114,22 +3202,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; @@ -3149,13 +3235,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"); } @@ -3167,12 +3253,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"); } @@ -3180,62 +3266,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"); } @@ -3243,99 +3327,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: @@ -3343,21 +3425,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; } @@ -3369,44 +3451,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) @@ -3420,12 +3501,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; @@ -3439,20 +3520,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) @@ -3460,24 +3540,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) @@ -3490,8 +3570,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: @@ -3499,8 +3579,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"); } @@ -3513,9 +3593,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 */ @@ -3530,7 +3610,7 @@ GetRPCRequest(StringInfo message) /* get the SP cursor Prepared handle */ GetSPCursorPreparedHandleParameter(request); - return (TDSRequest)request; + return (TDSRequest) request; } void @@ -3541,7 +3621,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; } @@ -3552,7 +3633,7 @@ ProcessRPCRequest(TDSRequest request) req = (TDSRequestSP) request; - switch(req->spType) + switch (req->spType) { case SP_CURSOR: GenerateBindParamsData(req); @@ -3608,6 +3689,7 @@ bool TdsIsSPPrepare() { TDSRequestSP req; + req = (TDSRequestSP) TdsRequestCtrl->request; if (req->spType == SP_PREPARE) return true; @@ -3628,8 +3710,8 @@ TdsIsSPPrepare() void TdsFetchInParamValues(ParamListInfo params) { - ParameterToken token; - TDSRequest request = TdsRequestCtrl->request; + ParameterToken token; + TDSRequest request = TdsRequestCtrl->request; TDSRequestSP req; int paramno = 0; @@ -3706,21 +3788,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 @@ -3739,17 +3824,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 */ @@ -3771,16 +3858,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); } @@ -3795,9 +3882,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)) @@ -3820,17 +3907,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; @@ -3850,17 +3936,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; @@ -3877,30 +3963,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; @@ -3909,7 +3996,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..6b3c0307f8 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdssecure.c @@ -38,14 +38,34 @@ #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 + +/* + * 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 */ static int -SslRead(BIO *h, char *buf, int size) +SslRead(BIO * h, char *buf, int size) { int res = 0; @@ -69,66 +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) +SslHandShakeRead(BIO * h, char *buf, int size) { 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; - - /* 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; - for (i = TDS_PACKET_HEADER_SIZE; i < res; i++) - { - buf[i - TDS_PACKET_HEADER_SIZE] = buf[i]; - } - res -= TDS_PACKET_HEADER_SIZE; + char *cur_loc; - /* - * 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; + if ((res = SslRead(h, buf, header_left)) <= 0) + return res; + + /* copy the header data read */ + cur_loc = &(pkt_data.buf[pkt_bytes_read]); + memcpy(cur_loc, buf, res); + pkt_bytes_read += res; + + header_left -= res; } + + 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); + + } + + /* 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; } @@ -136,9 +167,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 +191,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 +206,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 +222,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,8 +251,11 @@ 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) { + /* reset the tds packet data state*/ + pkt_bytes_read = 0; + if (my_bio_methods == NULL) { BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket(); @@ -269,8 +305,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..8acf94c751 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,14 +89,18 @@ 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(); { if (TDS_DEBUG_ENABLED(TDS_DEBUG2)) + { + HOLD_INTERRUPTS(); ereport(LOG, (errmsg("sql_batch statement: %s", query), errhidestmt(true))); + RESUME_INTERRUPTS(); + } PG_RE_THROW(); } @@ -106,6 +112,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 +135,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..ff880b19b8 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,26 @@ 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, + extra_ticks = 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,43 +229,44 @@ 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. We add the number of extra ticks to final value based + * on the unit digit milliseconds. */ switch (unit) { case 0: case 1: - round_val = 0; + extra_ticks = 0; break; case 2: case 3: case 4: - round_val = 3; - /* slightly different from default tick value at 7th decimal place */ - tick = 3.3333332; + extra_ticks = 1; break; case 5: case 6: case 7: case 8: - round_val = 7; + extra_ticks = 2; break; case 9: - round_val = 10; + extra_ticks = 3; break; default: break; } - msec = msec - unit + round_val; + msec = msec - unit; } 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) + extra_ticks; + } /* @@ -255,23 +274,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 +299,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; - int offset2; - if (x <= remDays) + 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 +337,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 +352,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 +362,31 @@ 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; + Assert((int) numTicks >= 0); + numMilli = (int) (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 +418,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 +459,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 +548,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 f84e7144ff..18198a6a3a 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,43 @@ 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); /* Local structures for the Function Cache by TDS Type ID */ typedef struct FunctionCacheByTdsIdKey @@ -129,8 +139,8 @@ typedef struct FunctionCacheByTdsIdKey typedef struct FunctionCacheByTdsIdEntry { - FunctionCacheByTdsIdKey key; - TdsIoFunctionData data; + FunctionCacheByTdsIdKey key; + TdsIoFunctionData data; } FunctionCacheByTdsIdEntry; /* @@ -144,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; } } @@ -188,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; } } @@ -228,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; } @@ -266,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); @@ -291,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); @@ -311,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 */ @@ -332,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; } @@ -360,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. */ @@ -428,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 */ @@ -439,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; @@ -492,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; @@ -513,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; @@ -541,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 @@ -580,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); } @@ -608,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); } @@ -831,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); } @@ -839,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; } } @@ -876,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; } } @@ -902,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; } @@ -919,7 +1011,7 @@ TdsTypeVarcharToDatum(StringInfo buf, pg_enc encoding, uint8_t tdsColDataType) Datum TdsTypeNCharToDatum(StringInfo buf) { - void *result; + void *result; StringInfoData temp; initStringInfo(&temp); @@ -934,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); @@ -970,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 */ { @@ -988,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); @@ -1000,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; @@ -1052,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); @@ -1067,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; @@ -1082,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. */ @@ -1124,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); @@ -1141,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; @@ -1150,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; @@ -1190,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() */ @@ -1206,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; @@ -1214,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. */ @@ -1224,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 @@ -1247,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 @@ -1261,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); /* @@ -1285,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); @@ -1306,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(); @@ -1317,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; @@ -1325,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); @@ -1345,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; @@ -1374,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); @@ -1391,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)); @@ -1408,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)); @@ -1424,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)); @@ -1441,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)); @@ -1458,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)); @@ -1475,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)); @@ -1491,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); @@ -1507,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); @@ -1538,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) { @@ -1553,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) @@ -1569,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)) @@ -1599,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) @@ -1618,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); @@ -1635,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); @@ -1653,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]; @@ -1675,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); @@ -1692,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); @@ -1713,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); @@ -1733,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); @@ -1743,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); } /* -------------------------------- @@ -1762,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); } /* -------------------------------- @@ -1775,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); @@ -1792,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); @@ -1809,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); @@ -1826,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); @@ -1841,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; @@ -1858,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; @@ -1882,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 */ { @@ -1903,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; @@ -1912,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); @@ -1925,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; @@ -1965,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; @@ -1983,6 +2099,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", + 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); + } + + 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", + 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); + } + 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,54 +2154,91 @@ TdsRecvTypeNumeric(const char *message, const ParameterToken token) 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; - TvpLookupItem *item; + bool xactStarted = IsTransactionOrTransactionBlock(); + char *finalTableName; + char *tvpTypeName; + TvpLookupItem *item; + temp = palloc(sizeof(StringInfoData)); initStringInfo(temp); TDSInstrumentation(INSTR_TDS_DATATYPE_TABLE_VALUED_PARAMETER); - /* Setting a unique name for TVP temp table. */ - tableName = psprintf("%s_TDS_TVP_TEMP_TABLE_%d", token->tvpInfo->tableName, rand()); + tvpTypeName = downcase_truncate_identifier(token->tvpInfo->tvpTypeName, + strlen(token->tvpInfo->tvpTypeName), true); /* - * We change the dialect to postgres to create temp tables - * and execute a prep/exec insert query via SPI. + * If schema is provided we convert it to physical schema and then update + * the tvpTypeName to have 2 part names. */ - set_config_option("babelfishpg_tsql.sql_dialect", "postgres", - (superuser() ? PGC_SUSET : PGC_USERSET), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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); + "with return code %d", rc); + + + /* + * 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", + GUC_CONTEXT_CONFIG, + 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)", - tableName, token->tvpInfo->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); if (rc != SPI_OK_UTILITY) + { + /* Reset dialect. */ + set_config_option("babelfishpg_tsql.sql_dialect", "tsql", + 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); + } SPI_finish(); PopActiveSnapshot(); @@ -2046,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); @@ -2072,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') @@ -2141,28 +2343,44 @@ 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", 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", + 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); + "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", + 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); + } SPI_finish(); PopActiveSnapshot(); @@ -2171,25 +2389,24 @@ 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); + GUC_CONTEXT_CONFIG, + 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); } 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), - true); + strlen(token->paramMeta.colName.data), + true); item->tableRelid = InvalidOid; item->tableName = finalTableName; tvp_lookup_list = lappend(tvp_lookup_list, item); @@ -2204,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); @@ -2222,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) @@ -2237,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) @@ -2251,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) @@ -2266,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) @@ -2281,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) @@ -2296,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) @@ -2311,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) @@ -2322,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) { @@ -2334,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); @@ -2359,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); @@ -2375,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; @@ -2384,18 +2601,22 @@ 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; + int copyLen = 0; + TdsColumnMetaData *col = (TdsColumnMetaData *) vMetaData; maxLen = col->metaEntry.type7.maxSize; - buf = (bytea *)palloc0(sizeof(bytea) * maxLen); + copyLen = Max((sizeof(bytea) * maxLen), VARSIZE_ANY_EXHDR(vlena)); + + buf = (bytea *) palloc0(copyLen); memcpy(buf, VARDATA_ANY(vlena), VARSIZE_ANY_EXHDR(vlena)); if ((rc = TdsPutUInt16LE(maxLen)) == 0) TdsPutbytes(buf, maxLen); - + pfree(buf); return rc; } @@ -2403,12 +2624,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); @@ -2425,7 +2648,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); @@ -2439,13 +2662,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); @@ -2465,10 +2690,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); @@ -2484,21 +2711,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); @@ -2509,11 +2736,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(); @@ -2530,9 +2758,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); @@ -2548,9 +2777,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(); @@ -2558,21 +2787,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); @@ -2584,10 +2813,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)); @@ -2595,16 +2825,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') @@ -2621,7 +2851,7 @@ TdsSendTypeNVarchar(FmgrInfo *finfo, Datum value, void *vMetaData) rc = TdsSendPlpDataHelper(buf.data, buf.len); } - pfree(buf.data); + pfree(buf.data); return rc; } @@ -2629,22 +2859,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) { @@ -2654,9 +2884,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) @@ -2666,7 +2896,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); @@ -2678,9 +2908,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); @@ -2688,7 +2920,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) @@ -2702,9 +2934,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); @@ -2712,13 +2946,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) @@ -2729,13 +2963,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) @@ -2749,13 +2985,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); @@ -2769,13 +3007,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) @@ -2795,13 +3035,19 @@ 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, + outlen = 0; + 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 target_precision = 0; out = OutputFunctionCall(finfo, value); if (out[0] == '-') @@ -2811,11 +3057,13 @@ 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)); + outlen = strlen(out) + max_scale; + decString = (char *) palloc(sizeof(char) * (outlen + 1)); /* While there is still digit in out and we haven't reached max_scale */ while (*out && scale < max_scale) { @@ -2836,22 +3084,34 @@ TdsSendTypeNumeric(FmgrInfo *finfo, Datum value, void *vMetaData) if (scale == -1) scale = 0; + /* Perform the overflow check before scribbling on to decString. */ + target_precision = precision + (max_scale - scale); + if (target_precision > TDS_MAX_NUM_PRECISION || + target_precision > max_precision) + ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Arithmetic overflow error for data type numeric."))); + /* - * 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) { decString[precision++] = '0'; } decString[precision] = '\0'; + Assert(precision == target_precision); - 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."))); + /* + * Verify that we did not go beyond the memory allocated. + * We allow precision < outlen. Consider the case when + * out="123.456", max_scale=8. Then by the end, precision=11 + * but outlen=15. + */ + Assert(precision <= outlen); if (precision >= 1 && precision < 10) length = 4; @@ -2910,23 +3170,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; @@ -2938,13 +3201,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; @@ -2953,22 +3216,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; @@ -2980,11 +3247,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; @@ -2993,7 +3260,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; } @@ -3002,70 +3270,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); @@ -3076,11 +3352,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 || @@ -3105,19 +3381,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); @@ -3125,18 +3401,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); @@ -3145,8 +3422,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); @@ -3157,8 +3434,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); @@ -3168,8 +3445,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); @@ -3179,11 +3456,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; @@ -3200,25 +3477,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) @@ -3227,7 +3504,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); @@ -3238,11 +3515,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; @@ -3253,7 +3530,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); @@ -3261,7 +3538,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); @@ -3272,8 +3549,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]; @@ -3284,7 +3562,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 @@ -3315,7 +3593,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 { @@ -3327,8 +3605,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); @@ -3344,7 +3622,7 @@ TdsTypeSqlVariantToDatum(StringInfo buf) } pltsql_plugin_handler_ptr->sqlvariant_set_metadata(result, - pgBaseType, scale, precision, maxLen); + pgBaseType, scale, precision, maxLen); buf->cursor += tempLen; @@ -3355,36 +3633,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; @@ -3393,7 +3687,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; @@ -3404,8 +3698,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); @@ -3430,14 +3724,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); @@ -3445,12 +3742,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; @@ -3461,10 +3758,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); @@ -3475,12 +3772,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) @@ -3490,7 +3787,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; @@ -3505,7 +3802,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; @@ -3516,7 +3813,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) { @@ -3548,7 +3845,7 @@ TdsSendTypeSqlvariant(FmgrInfo *finfo, Datum value, void *vMetaData) { /* * dataformat : totalLen(4B) + baseType(1B) + metadatalen(1B) + - * data(3B) + * data(3B) */ if (variantBaseType == VARIANT_TYPE_DATE) @@ -3563,15 +3860,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); @@ -3579,9 +3877,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) { @@ -3597,10 +3896,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; @@ -3628,12 +3927,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; @@ -3645,8 +3944,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); @@ -3658,15 +3957,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; @@ -3677,8 +3977,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; @@ -3700,10 +4000,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); @@ -3716,19 +4016,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); @@ -3739,9 +4042,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; @@ -3753,20 +4057,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: @@ -3786,21 +4091,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); @@ -3816,42 +4122,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..55fa42135a 100644 --- a/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c +++ b/contrib/babelfishpg_tds/src/backend/tds/tdsutils.c @@ -35,35 +35,37 @@ #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_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); 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); +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); 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 +133,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 +186,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 +197,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 +243,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 +280,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 +315,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 +342,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 +363,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 +396,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 +426,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 +448,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 +464,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 +482,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 +521,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 +604,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 +649,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 +673,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 +696,34 @@ 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; + 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; } /* - * 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 +737,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 +761,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; + ListCell *item = NULL; - /* We should not be handling superusers */ - Assert(!superuser()); - Assert(NULL != drop_role_stmt); + /* 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; + /* + * 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); + /* 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; + /* 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; + check_babelfish_droprole_restrictions(role); + pfree(role); + role = NULL; + } + return true; } /* @@ -792,21 +804,22 @@ handle_drop_role (DropRoleStmt* drop_role_stmt) static char * get_role_name(RoleSpec *role) { - Assert(NULL != 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); + /* + * 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,17 +893,17 @@ 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 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, @@ -904,11 +917,14 @@ 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; + 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 */ + 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; @@ -916,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; } @@ -928,62 +955,213 @@ 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); + 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); + /* + * 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) + { + 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) - { - 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; + 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 be owner */ + if (!pg_database_ownercheck(target_db_id, GetUserId())) + return true; - /* must have createdb rights */ - if (!have_createdb_privilege()) - return true; + /* must have createdb rights */ + if (!have_createdb_privilege()) + return true; - check_babelfish_renamedb_restrictions(target_db_id); - } - return true; + check_babelfish_renamedb_restrictions(target_db_id); + } + return true; } /* - * 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; + HeapTuple tp; + Form_pg_authid authForm = NULL; + + /* 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)) + { + tp = SearchSysCache1(AUTHNAME, CStringGetDatum(name)); + if (HeapTupleIsValid(tp)) + { + authForm = (Form_pg_authid) GETSTRUCT(tp); + } + babelfish_db_name = GetConfigOption("babelfishpg_tsql.database_name", true, false); + if(babelfish_db_name) + { + 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 ((authForm && authForm->rolcanlogin) && (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; + } + } + } + if (authForm) + ReleaseSysCache(tp); + 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(sql_dialect != SQL_DIALECT_TSQL && 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; } /* @@ -1017,15 +1195,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 +1221,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 +1242,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 +1272,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 +1304,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 +1313,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 56a29aa61f..b85d850543 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,16 +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 *MyTdsLibraryName; +extern PGDLLIMPORT char *MyTdsHostName; +extern PGDLLIMPORT char *MyTdsContextInfo; extern PGDLLIMPORT uint32_t MyTdsClientPid; extern PGDLLIMPORT uint32_t MyTdsProtocolVersion; extern PGDLLIMPORT uint32_t MyTdsPacketSize; @@ -226,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; @@ -238,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; @@ -251,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 */ @@ -289,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); @@ -329,7 +332,10 @@ 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 uint32_t get_tds_client_pid(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[], @@ -357,14 +363,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 48aa1f7179..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,59 +476,50 @@ 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; - char *db_name = pltsql_plugin_handler_ptr->get_cur_db_name(); - char *physical_schema = NULL; - 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) - 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; @@ -525,11 +530,10 @@ 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))); } } - pfree(db_name); temp->tvpInfo->tableName = tempStringInfo->data; i = 0; @@ -541,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; @@ -548,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); @@ -567,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: @@ -576,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) @@ -674,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); @@ -693,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) { @@ -763,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; @@ -786,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); @@ -827,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 @@ -870,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 @@ -906,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 ae39974f05..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,130 +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 *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 @@ -327,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 @@ -341,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 @@ -355,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; @@ -380,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); @@ -473,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_tds/test/TDSNode.pm b/contrib/babelfishpg_tds/test/TDSNode.pm index a3f094acc2..d767b02235 100644 --- a/contrib/babelfishpg_tds/test/TDSNode.pm +++ b/contrib/babelfishpg_tds/test/TDSNode.pm @@ -22,7 +22,8 @@ sub new { _node => $node, _tsql_port => 1433, _tsql_master_role => '', - _tsql_master_db => '' + _tsql_master_db => '', + _tsql_migration_mode => '', }; bless $self, $class; @@ -49,7 +50,7 @@ sub tsql_master_db { } sub init_tsql { - my ($self, $role, $testdb) = @_; + my ($self, $role, $testdb, $migration_mode) = @_; my $node = $self->{_node}; if (!defined($role) or ($role eq "")) @@ -62,8 +63,14 @@ sub init_tsql { die "cannot initialize babelfish, master database is empty"; } + if (!defined($migration_mode) or ($migration_mode eq "")) + { + $migration_mode = "single-db"; + } + $self->{_tsql_master_role} = $role; $self->{_tsql_master_db} = $testdb; + $self->{_tsql_migration_mode} = $migration_mode; $node->safe_psql('postgres', qq{CREATE USER $role WITH SUPERUSER CREATEDB CREATEROLE PASSWORD '12345678' INHERIT}); $node->safe_psql('postgres', qq{CREATE DATABASE $testdb OWNER $role}); @@ -71,6 +78,7 @@ sub init_tsql { $node->safe_psql($testdb, qq{GRANT ALL ON SCHEMA sys to $role}); $node->safe_psql($testdb, qq{ALTER USER $role CREATEDB}); $node->safe_psql($testdb, qq{ALTER SYSTEM SET babelfishpg_tsql.database_name = '$testdb'}); + $node->safe_psql($testdb, qq{ALTER SYSTEM SET babelfishpg_tsql.migration_mode = '$migration_mode'}); $node->safe_psql($testdb, qq{SELECT pg_reload_conf()}); $node->safe_psql($testdb, qq{CALL sys.initialize_babelfish('$role')}); } diff --git a/contrib/babelfishpg_tds/test/t/004_bbfdumprestore.pl b/contrib/babelfishpg_tds/test/t/004_bbfdumprestore.pl new file mode 100644 index 0000000000..fa1e6592ba --- /dev/null +++ b/contrib/babelfishpg_tds/test/t/004_bbfdumprestore.pl @@ -0,0 +1,199 @@ +# Set of tests for Babelfish dump/restore to test blocked options, +# including cross-version and cross-migration checks. +use strict; +use warnings; + +use Cwd qw(abs_path); +use File::Basename qw(dirname); +use PostgreSQL::Test::Utils; +use PostgreSQL::Test::Cluster; +use Test::More; +use TDSNode; + +# This test requires two clusters, an old one to dump and a new one in +# which we will restore. Below environment variable is required to be set: +# - "oldinstall", to point to the installation path of the old cluster. +if (!defined($ENV{oldinstall})) +{ + # oldinstall is not defined, so leave and die if test is + # done with an older installation. + die "oldinstall is undefined"; +} + +# Paths to the dumps taken during the tests. +my $tempdir = PostgreSQL::Test::Utils::tempdir; +my $dump1_file = "$tempdir/dump_all_old.sql"; +my $dump2_file = "$tempdir/dump_db_old.sql"; +my $dump3_file = "$tempdir/dump_all_new.sql"; +my $dump4_file = "$tempdir/dump_db_new.custom"; + +############################################################################################ +############################### Test for cross version mode ################################ +############################################################################################ + +# Initialize old node to dump +my $oldnode = + PostgreSQL::Test::Cluster->new('old_node', + install_path => $ENV{oldinstall}); +$oldnode->init; +$oldnode->append_conf( + 'postgresql.conf', qq{ + log_connections = on + listen_addresses='127.0.0.1' + shared_preload_libraries = 'babelfishpg_tds' + lc_messages = 'C' +}); +$oldnode->start; +# Initialize Babelfish in old node +my $tsql_oldnode = new TDSNode($oldnode); +$tsql_oldnode->init_tsql('test_master', 'testdb'); +$oldnode->stop; + +# Initialize a new node for the restore. +my $newnode = PostgreSQL::Test::Cluster->new('new_node'); +$newnode->init; +$newnode->append_conf( + 'postgresql.conf', qq{ + log_connections = on + listen_addresses='127.0.0.1' + shared_preload_libraries = 'babelfishpg_tds' + lc_messages = 'C' +}); +$newnode->start; +# Initialize Babelfish in new node +my $tsql_newnode = new TDSNode($newnode); +$tsql_newnode->init_tsql('test_master', 'testdb'); +$newnode->stop; + +# Dump global objects using pg_dumpall. Note that we +# need to use dump utilities from the new node here. +$oldnode->start; +my @dumpall_command = ( + 'pg_dumpall', '--database', 'testdb', '--username', 'test_master', + '--port', $oldnode->port, '--roles-only', '--quote-all-identifiers', + '--verbose', '--no-role-passwords', '--file', $dump1_file); +$newnode->command_ok(\@dumpall_command, 'Dump global objects.'); +# Dump Babelfish database using pg_dump. +my @dump_command = ( + 'pg_dump', '--username', 'test_master', '--quote-all-identifiers', + '--port', $oldnode->port, '--verbose', '--dbname', 'testdb', + '--file', $dump2_file); +$newnode->command_ok(\@dump_command, 'Dump Babelfish database.'); +$oldnode->stop; + +# Retore the dumped files on the new server. +$newnode->start; + +# Restore of dumpall file should cause a failure since cross version +# dump/restore is not yet supported. +$newnode->command_fails_like( + [ + 'psql', + '-d', 'testdb', + '-U', 'test_master', + '-p', $newnode->port, + '--single-transaction', + '-f', $dump1_file, + ], + qr/Dump and restore across different Postgres versions is not yet supported./, + 'Restore of global objects failed since source and target versions do not match.'); + +# Similarly, restore of dump file should also cause a failure. +$newnode->command_fails_like( + [ + 'psql', + '-d', 'testdb', + '-U', 'test_master', + '-p', $newnode->port, + '--single-transaction', + '-f', $dump2_file, + ], + qr/Dump and restore across different Postgres versions is not yet supported./, + 'Restore of Babelfish database failed since source and target versions do not match.'); +$newnode->stop; + +############################################################################################ +############################## Test for cross migration mode ############################### +############################################################################################ + +# Initialize a node with the current version to dump. +my $newnode2 = PostgreSQL::Test::Cluster->new('new_node2'); +$newnode2->init; +$newnode2->append_conf( + 'postgresql.conf', qq{ + log_connections = on + listen_addresses='127.0.0.1' + shared_preload_libraries = 'babelfishpg_tds' + lc_messages = 'C' +}); +$newnode2->start; +# Initialize Babelfish in new node +my $tsql_newnode2 = new TDSNode($newnode2); +$tsql_newnode2->init_tsql('test_master', 'testdb', 'multi-db'); + +# Dump global objects using pg_dumpall. Note that we +# need to use dump utilities from the new node here. +@dumpall_command = ( + 'pg_dumpall', '--database', 'testdb', '--username', 'test_master', + '--port', $newnode2->port, '--roles-only', '--quote-all-identifiers', + '--verbose', '--no-role-passwords', '--file', $dump3_file); +$newnode2->command_ok(\@dumpall_command, 'Dump global objects.'); +# Dump Babelfish database using pg_dump. Let's dump with the custom format +# this time so that we cover pg_restore as well. +@dump_command = ( + 'pg_dump', '--username', 'test_master', '--quote-all-identifiers', + '--port', $newnode2->port, '--verbose', '--dbname', 'testdb', + '--format', 'custom', '--file', $dump4_file); +$newnode2->command_ok(\@dump_command, 'Dump Babelfish database.'); +$newnode2->stop; + +# Retore the dumped files on the new server. +$newnode->start; + +# Restore of dumpall file should cause a failure since cross migration mode +# dump/restore is not yet supported. +$newnode->command_fails_like( + [ + 'psql', + '-d', 'testdb', + '-U', 'test_master', + '-p', $newnode->port, + '--single-transaction', + '-f', $dump3_file, + ], + qr/Dump and restore across different migration modes is not yet supported./, + 'Restore of global objects failed since source and target migration modes do not match.'); + +# Similarly, restore of dump file should also cause a failure. +$newnode->command_fails_like( + [ + 'pg_restore', + '-d', 'testdb', + '-U', 'test_master', + '-p', $newnode->port, + '--single-transaction', + $dump4_file, + ], + qr/Dump and restore across different migration modes is not yet supported./, + 'Restore of Babelfish database failed since source and target migration modes do not match.'); +$newnode->stop; + +############################################################################################ +########################### Test dump for non Babelfish database ########################### +############################################################################################ +$newnode->start; + +# Dump global objects using pg_dumpall. +@dumpall_command = ( + 'pg_dumpall', '--database', 'postgres', '--port', $newnode->port, + '--roles-only', '--quote-all-identifiers', '--verbose', + '--no-role-passwords', '--file', $dump1_file); +$newnode->command_ok(\@dumpall_command, 'Dump global objects.'); +# Dump Babelfish database using pg_dump. +@dump_command = ( + 'pg_dump', '--quote-all-identifiers', '--port', $newnode->port, + '--verbose', '--dbname', 'postgres', + '--file', $dump2_file); +$newnode->command_ok(\@dump_command, 'Dump non-Babelfish (postgres db) database.'); +$newnode->stop; +done_testing(); diff --git a/contrib/babelfishpg_tsql/Makefile b/contrib/babelfishpg_tsql/Makefile index ffb564162f..f2ef072a5b 100644 --- a/contrib/babelfishpg_tsql/Makefile +++ b/contrib/babelfishpg_tsql/Makefile @@ -72,28 +72,28 @@ OBJS += src/tsql_for/forxml.o OBJS += src/tsql_for/forxml_old.o OBJS += src/tsql_analyze.o OBJS += src/linked_servers.o +OBJS += src/table_variable_mvcc.o +OBJS += src/extendedproperty.o +OBJS += src/fts.o +OBJS += src/fts_parser.o export ANTLR4_JAVA_BIN=java 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 +PG_CXXFLAGS += -g -Werror -Wfloat-conversion PG_CXXFLAGS += -Wno-deprecated -Wno-error=attributes -Wno-suggest-attribute=format # disable some warnings from ANTLR runtime header PG_CXXFLAGS += -Wno-undef -Wall -Wcpp PG_CXXFLAGS += -Wno-register # otherwise C++17 gags on PostgreSQL headers PG_CXXFLAGS += -I$(ANTLR4_RUNTIME_INCLUDE_DIR) -PG_CFLAGS += -g -Werror +PG_CFLAGS += -g -Werror -Wfloat-conversion 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 -Wfloat-conversion -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)) @@ -242,6 +242,10 @@ src/backend_parser/scan-backend.c: src/backend_parser/scan-backend.l # Force these dependencies to be known even without dependency info built: src/backend_parser/gram-backend.o src/backend_parser/scan-backend.o src/backend_parser/parser.o: src/backend_parser/gram-backend.h +src/fts_parser.o: src/fts_scan.c src/fts_data.h +src/fts.o: src/fts_scan.c src/fts_parser.c src/fts_data.h +distprep: src/fts_scan.c src/fts_parser.c + include $(PGXS) .DEFAULT_GOAL := all diff --git a/contrib/babelfishpg_tsql/Version.config b/contrib/babelfishpg_tsql/Version.config index 9d7288b84a..ec4d6a892b 100644 --- a/contrib/babelfishpg_tsql/Version.config +++ b/contrib/babelfishpg_tsql/Version.config @@ -2,6 +2,6 @@ # places during the build process PGTSQL_MAJOR_VERSION=3 -PGTSQL_MINOR_VERSION=2 +PGTSQL_MINOR_VERSION=5 PGTSQL_MICRO_VERSION=0 diff --git a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 index be9ddfa269..53707785c5 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlLexer.g4 @@ -155,16 +155,22 @@ CHANGETABLE: C H A N G E T A B L E; CHANGE_RETENTION: C H A N G E UNDERLINE R E T E N T I O N; CHANGE_TRACKING: C H A N G E UNDERLINE T R A C K I N G; CHECK: C H E C K; +CHECKDB: C H E C K D B; +CHECKFILEGROUP: C H E C K F I L E G R O U P; +CHECKIDENT: C H E C K I D E N T; CHECKPOINT: C H E C K P O I N T; CHECKSUM: C H E C K S U M; CHECKSUM_AGG: C H E C K S U M UNDERLINE A G G; +CHECKTABLE: C H E C K T A B L E; CHECK_EXPIRATION: C H E C K UNDERLINE E X P I R A T I O N; CHECK_POLICY: C H E C K UNDERLINE P O L I C Y; CLASSIFIER: C L A S S I F I E R; CLASSIFIER_FUNCTION: C L A S S I F I E R UNDERLINE F U N C T I O N; CLEANUP: C L E A N U P; +CLEANTABLE: C L E A N T A B L E; CLEANUP_POLICY: C L E A N U P UNDERLINE P O L I C Y; CLEAR: C L E A R; +CLONEDATABASE: C L O N E D A T A B A S E; CLOSE: C L O S E; CLUSTER: C L U S T E R; CLUSTERED: C L U S T E R E D; @@ -237,15 +243,18 @@ DATASPACE: D A T A S P A C E; DATEADD: D A T E A D D; DATEDIFF: D A T E D I F F; DATEDIFF_BIG: D A T E D I F F UNDERLINE B I G; +DATE_BUCKET: D A T E UNDERLINE B U C K E T; DATEFIRST: D A T E F I R S T; DATEFORMAT: D A T E F O R M A T; DATE_FORMAT: D A T E UNDERLINE F O R M A T; DATENAME: D A T E N A M E; DATEPART: D A T E P A R T; +DATETRUNC: D A T E T R U N C; DATE_CORRELATION_OPTIMIZATION: D A T E UNDERLINE C O R R E L A T I O N UNDERLINE O P T I M I Z A T I O N; DAY: D A Y; DAYS: D A Y S; DBCC: D B C C; +DBREINDEX: D B R E I N D E X; DB_CHAINING: D B UNDERLINE C H A I N I N G; DB_FAILOVER: D B UNDERLINE F A I L O V E R; DDL: D D L; @@ -296,6 +305,7 @@ DOLLAR_ROWGUID: DOLLAR R O W G U I D; DOLLAR_TO_ID: DOLLAR T O UNDERLINE I D; // graph DOUBLE: D O U B L E; DROP: D R O P; +DROPCLEANBUFFERS: D R O P C L E A N B U F F E R S; DTC_SUPPORT: D T C UNDERLINE S U P P O R T; DUMP: D U M P; DYNAMIC: D Y N A M I C; @@ -385,6 +395,9 @@ FORMAT: F O R M A T; FORWARD_ONLY: F O R W A R D UNDERLINE O N L Y; FORMAT_OPTIONS: F O R M A T UNDERLINE O P T I O N S; FORMAT_TYPE: F O R M A T UNDERLINE T Y P E; +FREEPROCCACHE: F R E E P R O C C A C H E; +FREESESSIONCACHE: F R E E S E S S I O N C A C H E; +FREESYSTEMCACHE: F R E E S Y S T E M C A C H E; FREETEXT: F R E E T E X T; FREETEXTTABLE: F R E E T E X T T A B L E; FROM: F R O M; @@ -422,6 +435,7 @@ HASHED: H A S H E D; HAVING: H A V I N G; HEALTHCHECKTIMEOUT: H E A L T H C H E C K T I M E O U T; HEALTH_CHECK_TIMEOUT: H E A L T H UNDERLINE C H E C K UNDERLINE T I M E O U T; +HELP: H E L P; HIDDEN_RENAMED: H I D D E N; HIGH: H I G H; HINT: H I N T; @@ -431,6 +445,7 @@ HOLDLOCK: H O L D L O C K; HONOR_BROKER_PRIORITY: H O N O R UNDERLINE B R O K E R UNDERLINE P R I O R I T Y; HOUR: H O U R; HOURS: H O U R S; +INDEXDEFRAG: I N D E X D E F R A G; IDENTITY: I D E N T I T Y; IDENTITYCOL: I D E N T I T Y C O L; IDENTITY_INSERT: I D E N T I T Y UNDERLINE I N S E R T; @@ -453,6 +468,7 @@ INIT: I N I T; INITIATOR: I N I T I A T O R; INNER: I N N E R; INPUT: I N P U T; +INPUTBUFFER: I N P U T B U F F E R; INSENSITIVE: I N S E N S I T I V E; INSERT: I N S E R T; INSERTED: I N S E R T E D; @@ -601,6 +617,7 @@ NONE: N O N E; NON_TRANSACTED_ACCESS: N O N UNDERLINE T R A N S A C T E D UNDERLINE A C C E S S; NORECOMPUTE: N O R E C O M P U T E; NORECOVERY: N O R E C O V E R Y; +NORESEED: N O R E S E E D; NOREWIND: N O R E W I N D; NOSKIP: N O S K I P; NOT: N O T; @@ -641,6 +658,7 @@ OPENDATASOURCE: O P E N D A T A S O U R C E; OPENJSON: O P E N J S O N; OPENQUERY: O P E N Q U E R Y; OPENROWSET: O P E N R O W S E T; +OPENTRAN: O P E N T R A N; OPENXML: O P E N X M L; OPEN_EXISTING: O P E N UNDERLINE E X I S T I N G; OPERATIONS: O P E R A T I O N S; @@ -653,6 +671,7 @@ ORDER: O R D E R; OUT: O U T; OUTER: O U T E R; OUTPUT: O U T P U T; +OUTPUTBUFFER: O U T P U T B U F F E R; OVER: O V E R; OVERRIDE: O V E R R I D E; OWNER: O W N E R; @@ -709,6 +728,7 @@ PRIVATE: P R I V A T E; PRIVATE_KEY: P R I V A T E UNDERLINE K E Y; PRIVILEGES: P R I V I L E G E S; PROC: P R O C; +PROCCACHE: P R O C C A C H E; PROCEDURE: P R O C E D U R E; PROCEDURE_CACHE: P R O C E D U R E UNDERLINE C A C H E; PROCEDURE_NAME: P R O C E D U R E UNDERLINE N A M E; @@ -779,6 +799,7 @@ REQUEST_MEMORY_GRANT_TIMEOUT_SEC: R E Q U E S T UNDERLINE M E M REQUIRED: R E Q U I R E D; REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT: R E Q U I R E D UNDERLINE S Y N C H R O N I Z E D UNDERLINE S E C O N D A R I E S UNDERLINE T O UNDERLINE C O M M I T; RESAMPLE: R E S A M P L E; +RESEED: R E S E E D; RESERVE_DISK_SPACE: R E S E R V E UNDERLINE D I S K UNDERLINE S P A C E; RESET: R E S E T; RESOURCE: R E S O U R C E; @@ -869,10 +890,14 @@ SETS: S E T S; SETTINGS: S E T T I N G S; SETUSER: S E T U S E R; SHARE: S H A R E; +SHOWCONTIG: S H O W C O N T I G; SHOWPLAN: S H O W P L A N; SHOWPLAN_ALL: S H O W P L A N UNDERLINE A L L; SHOWPLAN_TEXT: S H O W P L A N UNDERLINE T E X T; SHOWPLAN_XML: S H O W P L A N UNDERLINE X M L; +SHOW_STATISTICS: S H O W UNDERLINE S T A T I S T I C S; +SHRINKDATABASE: S H R I N K D A T A B A S E; +SHRINKFILE: S H R I N K F I L E; SHRINKLOG: S H R I N K L O G; SHUTDOWN: S H U T D O W N; SID: S I D; @@ -897,6 +922,7 @@ SQL: S Q L; SQLDUMPERFLAGS: S Q L D U M P E R F L A G S; SQLDUMPERPATH: S Q L D U M P E R P A T H; SQLDUMPERTIMEOUT: S Q L D U M P E R T I M E O U T S; +SQLPERF: S Q L P E R F; STALE_CAPTURE_POLICY_THRESHOLD: S T A L E UNDERLINE C A P T U R E UNDERLINE P O L I C Y UNDERLINE T H R E S H O L D; STALE_QUERY_THRESHOLD_DAYS: S T A L E UNDERLINE Q U E R Y UNDERLINE T H R E S H O L D UNDERLINE D A Y S; STANDBY: S T A N D B Y; @@ -968,7 +994,10 @@ TOSTRING: T O S T R I N G; TOTAL_COMPILE_CPU_TIME_MS: T O T A L UNDERLINE C O M P I L E UNDERLINE C P U UNDERLINE T I M E UNDERLINE M S; TOTAL_EXECUTION_CPU_TIME_MS: T O T A L UNDERLINE E X E C U T I O N UNDERLINE C P U UNDERLINE T I M E UNDERLINE M S; TRACE: T R A C E; +TRACEOFF: T R A C E O F F; +TRACEON: T R A C E O N; TRACKING: T R A C K I N G; +TRACESTATUS: T R A C E S T A T U S; TRACK_CAUSALITY: T R A C K UNDERLINE C A U S A L I T Y; TRACK_COLUMNS_UPDATED: T R A C K UNDERLINE C O L U M N S UNDERLINE U P D A T E D; TRAN: T R A N; @@ -1007,6 +1036,7 @@ UNPIVOT: U N P I V O T; UNSAFE: U N S A F E; UOW: U O W; UPDATE: U P D A T E; +UPDATEUSAGE: U P D A T E U S A G E; UPDATETEXT: U P D A T E T E X T; UPDLOCK: U P D L O C K; URL: U R L; @@ -1014,6 +1044,7 @@ USE: U S E; USE_TYPE_DEFAULT: U S E UNDERLINE T Y P E UNDERLINE D E F A U L T; USED: U S E D; USER: U S E R; +USEROPTIONS: U S E R O P T I O N S; USING: U S I N G; VALIDATION: V A L I D A T I O N; VALID_XML: V A L I D UNDERLINE X M L; diff --git a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 index 623526b0a2..b2836cf7be 100644 --- a/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 +++ b/contrib/babelfishpg_tsql/antlr/TSqlParser.g4 @@ -866,12 +866,12 @@ drop_xml_schema_collection // https://docs.microsoft.com/en-us/sql/t-sql/statements/disable-trigger-transact-sql disable_trigger - : DISABLE TRIGGER ( ( COMMA? (schema_name=id DOT)? trigger_name=id )+ | ALL) ON ((schema_id=id DOT)? object_name=id|DATABASE|ALL SERVER) + : DISABLE TRIGGER ( ( COMMA? schema_trigger_name )+ | ALL) ON (tabname=table_name|DATABASE|ALL SERVER) ; // https://docs.microsoft.com/en-us/sql/t-sql/statements/enable-trigger-transact-sql enable_trigger - : ENABLE TRIGGER ( ( COMMA? (schema_name=id DOT)? trigger_name=id )+ | ALL) ON ( (schema_id=id DOT)? object_name=id|DATABASE|ALL SERVER) + : ENABLE TRIGGER ( ( COMMA? schema_trigger_name )+ | ALL) ON (tabname=table_name|DATABASE|ALL SERVER) ; // https://docs.microsoft.com/en-us/sql/t-sql/statements/truncate-table-transact-sql @@ -1697,7 +1697,7 @@ merge_not_matched // https://msdn.microsoft.com/en-us/library/ms189835.aspx delete_statement : with_expression? - DELETE (TOP LR_BRACKET expression RR_BRACKET PERCENT? | TOP DECIMAL)? + DELETE (TOP LR_BRACKET expression RR_BRACKET PERCENT?)? FROM? delete_statement_from with_table_hints? output_clause? @@ -3094,19 +3094,53 @@ shutdown_statement ; dbcc_statement - : DBCC name=dbcc_command ( LR_BRACKET expression_list RR_BRACKET )? (WITH dbcc_options)? SEMI? + : DBCC CHECKIDENT ( LR_BRACKET table_name_string ( (COMMA NORESEED) | (COMMA RESEED (COMMA MINUS? new_value=(DECIMAL | FLOAT))?) )? RR_BRACKET ) (WITH dbcc_options)? SEMI? + | DBCC name=dbcc_command ( LR_BRACKET expression_list RR_BRACKET )? (WITH dbcc_options)? SEMI? //These are dbcc commands with strange syntax that doesn't fit the regular dbcc syntax | DBCC SHRINKLOG ( LR_BRACKET SIZE EQUAL (constant_expression| id | DEFAULT) (KB | MB | GB | TB)? RR_BRACKET )? (WITH dbcc_options)? SEMI? - ; + ; dbcc_command - : ID | keyword + : ID + | CHECKDB + | CHECKFILEGROUP + | CHECKTABLE + | CLEANTABLE + | CLONEDATABASE + | DBREINDEX + | DROPCLEANBUFFERS + | FREEPROCCACHE + | FREESESSIONCACHE + | FREESYSTEMCACHE + | HELP + | INDEXDEFRAG + | INPUTBUFFER + | OPENTRAN + | OUTPUTBUFFER + | PROCCACHE + | SHOW_STATISTICS + | SHOWCONTIG + | SHRINKDATABASE + | SHRINKFILE + | SQLPERF + | TRACEOFF + | TRACEON + | TRACESTATUS + | UPDATEUSAGE + | USEROPTIONS ; dbcc_options : ID (COMMA ID)? ; + +table_name_string + : table = id + | char_string + ; + + execute_as_clause : (EXECUTE|EXEC) AS (CALLER | SELF | OWNER | char_string) ; @@ -3156,7 +3190,7 @@ column_def_table_constraint // empirically found: ROWGUIDCOL can be in various locations column_definition : simple_column_name (data_type system_versioning_column? | AS expression PERSISTED? ) ( special_column_option | collation | null_notnull )* - ( column_constraint? IDENTITY (LR_BRACKET sign? seed=DECIMAL COMMA sign? increment=DECIMAL RR_BRACKET)? )? for_replication? ROWGUIDCOL? + ( column_constraint* IDENTITY (LR_BRACKET sign? seed=DECIMAL COMMA sign? increment=DECIMAL RR_BRACKET)? )? for_replication? ROWGUIDCOL? column_constraint* inline_index? | TIMESTAMP null_notnull? column_constraint? ; @@ -3164,7 +3198,7 @@ column_definition // Temporary workaround for COLLATE default in INSERT BULK insert_bulk_column_definition : simple_column_name (data_type system_versioning_column? | AS expression PERSISTED? ) ( special_column_option | (COLLATE (id | DEFAULT)) | null_notnull )* - ( column_constraint? IDENTITY (LR_BRACKET sign? seed=DECIMAL COMMA sign? increment=DECIMAL RR_BRACKET)? )? for_replication? ROWGUIDCOL? + ( column_constraint* IDENTITY (LR_BRACKET sign? seed=DECIMAL COMMA sign? increment=DECIMAL RR_BRACKET)? )? for_replication? ROWGUIDCOL? column_constraint* inline_index? ; @@ -3317,8 +3351,9 @@ set_special : SET set_on_off_option (COMMA set_on_off_option)* on_off | SET STATISTICS set_statistics_keyword (COMMA set_statistics_keyword)* on_off | SET OFFSETS set_offsets_keyword (COMMA set_offsets_keyword)* on_off + | SET special_variable LOCAL_ID | SET id_set=id (id_val=id | constant_LOCAL_ID | on_off) - | SET ROWCOUNT (LOCAL_ID | MINUS? DECIMAL) + | SET ROWCOUNT DECIMAL // https://msdn.microsoft.com/en-us/library/ms173763.aspx | SET (TRAN | TRANSACTION) ISOLATION LEVEL (READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SNAPSHOT | SERIALIZABLE | DECIMAL) // https://msdn.microsoft.com/en-us/library/ms188059.aspx @@ -3328,6 +3363,12 @@ set_special | SET BABELFISH_STATISTICS PROFILE on_off ; +special_variable + : DATEFIRST + | ROWCOUNT + | LANGUAGE + ; + set_on_off_option : ANSI_DEFAULTS | ANSI_NULLS @@ -3738,7 +3779,7 @@ freetext_function freetext_predicate : CONTAINS LR_BRACKET (full_column_name | LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET | (table_name DOT)? STAR | PROPERTY LR_BRACKET full_column_name COMMA expression RR_BRACKET ) COMMA expression RR_BRACKET - | FREETEXT LR_BRACKET table_name COMMA (full_column_name | LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET | (table_name DOT)? STAR ) COMMA expression (COMMA LANGUAGE expression)? RR_BRACKET + | FREETEXT LR_BRACKET (full_column_name | LR_BRACKET full_column_name (COMMA full_column_name)* RR_BRACKET | (table_name DOT)? STAR ) COMMA expression (COMMA LANGUAGE expression)? RR_BRACKET ; // these are functions with a different call syntax than regular functions; @@ -4266,15 +4307,20 @@ keyword | CHANGETABLE | CHANGE_RETENTION | CHANGE_TRACKING + | CHECKDB + | CHECKFILEGROUP | CHECKSUM | CHECKSUM_AGG + | CHECKTABLE | CHECK_EXPIRATION | CHECK_POLICY | CLASSIFIER | CLASSIFIER_FUNCTION + | CLEANTABLE | CLEANUP | CLEANUP_POLICY - | CLEAR + | CLEAR + | CLONEDATABASE | CLUSTER | COALESCE | COLLECTION @@ -4327,15 +4373,18 @@ keyword | DATEADD | DATEDIFF | DATEDIFF_BIG + | DATE_BUCKET | DATEFIRST | DATEFORMAT | DATE_FORMAT | DATENAME | DATEPART + | DATETRUNC | DATE_CORRELATION_OPTIMIZATION | DATE_FORMAT | DAY | DAYS + | DBREINDEX | DB_CHAINING | DB_FAILOVER | DDL @@ -4369,6 +4418,7 @@ keyword | DISTRIBUTED_AGG | DISTRIBUTION | DOCUMENT + | DROPCLEANBUFFERS | DTC_SUPPORT | DYNAMIC | EDGE @@ -4442,6 +4492,9 @@ keyword | FORMAT_OPTIONS | FORMAT_TYPE | FORWARD_ONLY + | FREEPROCCACHE + | FREESESSIONCACHE + | FREESYSTEMCACHE | FULLSCAN | FULLTEXT | GB @@ -4470,6 +4523,7 @@ keyword | HASHED | HEALTHCHECKTIMEOUT | HEALTH_CHECK_TIMEOUT + | HELP | HIDDEN_RENAMED | HIGH | HINT @@ -4492,10 +4546,12 @@ keyword | INCLUDE_NULL_VALUES | INCREMENT | INCREMENTAL + | INDEXDEFRAG | INFINITE | INIT | INITIATOR | INPUT + | INPUTBUFFER | INSENSITIVE | INSERTED | INSTEAD @@ -4661,6 +4717,7 @@ keyword | ONLY | ON_FAILURE | OPENJSON + | OPENTRAN | OPEN_EXISTING | OPERATIONS | OPERATION_MODE @@ -4668,6 +4725,7 @@ keyword | OPTIMIZE | OUT | OUTPUT + | OUTPUTBUFFER | OVERRIDE | OWNER | OWNERSHIP @@ -4715,6 +4773,7 @@ keyword | PRIVATE | PRIVATE_KEY | PRIVILEGES + | PROCCACHE | PROCEDURE_CACHE | PROCEDURE_NAME | PROCESS @@ -4843,10 +4902,14 @@ keyword | SETS | SETTINGS | SHARE + | SHOWCONTIG | SHOWPLAN | SHOWPLAN_ALL | SHOWPLAN_TEXT | SHOWPLAN_XML + | SHOW_STATISTICS + | SHRINKDATABASE + | SHRINKFILE | SHRINKLOG | SID | SIGNATURE @@ -4869,6 +4932,7 @@ keyword | SQLDUMPERFLAGS | SQLDUMPERPATH | SQLDUMPERTIMEOUT + | SQLPERF | STALE_CAPTURE_POLICY_THRESHOLD | STALE_QUERY_THRESHOLD_DAYS | STANDBY @@ -4930,6 +4994,9 @@ keyword | TOTAL_COMPILE_CPU_TIME_MS | TOTAL_EXECUTION_CPU_TIME_MS | TRACE + | TRACEOFF + | TRACEON + | TRACESTATUS | TRACKING | TRACK_CAUSALITY | TRACK_COLUMNS_UPDATED @@ -4959,8 +5026,10 @@ keyword | UNMASK | UNSAFE | UOW + | UPDATEUSAGE | URL | USED + | USEROPTIONS | USE_TYPE_DEFAULT | USING | VALIDATION @@ -5028,6 +5097,10 @@ simple_name : DOT? (schema=id? DOT)? name=id ; +schema_trigger_name + : (schema_name=id DOT)? trigger_name=id + ; + func_proc_name_schema : DOT? ((schema=id)? DOT)? procedure=id ; @@ -5092,8 +5165,8 @@ id | DOUBLE_QUOTE_ID // this is a double-quoted identifier in case of SET QUOTED_IDENTIFIER ON | SQUARE_BRACKET_ID | keyword - | DOLLAR_IDENTITY - | DOLLAR_ROWGUID + | DOLLAR_IDENTITY + | DOLLAR_ROWGUID | id colon_colon id ; 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/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_function.out b/contrib/babelfishpg_tsql/expected/test/babel_function.out deleted file mode 100644 index ab040f76fe..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 ----------------------------------------- - Mon Dec 26 16: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 15: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/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/runtime/functions.c b/contrib/babelfishpg_tsql/runtime/functions.c index 9adcfbbaef..95986f72fa 100644 --- a/contrib/babelfishpg_tsql/runtime/functions.c +++ b/contrib/babelfishpg_tsql/runtime/functions.c @@ -11,14 +11,20 @@ #include "catalog/pg_database.h" #include "catalog/pg_namespace.h" #include "catalog/pg_type.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_depend.h" #include "commands/dbcommands.h" #include "commands/extension.h" #include "common/md5.h" +#include "executor/spi.h" +#include "executor/spi_priv.h" #include "miscadmin.h" #include "parser/scansup.h" #include "tsearch/ts_locale.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/date.h" +#include "utils/datetime.h" #include "utils/elog.h" #include "utils/guc.h" #include "utils/lsyscache.h" @@ -39,6 +45,7 @@ #include "../src/multidb.h" #include "../src/session.h" #include "../src/catalog.h" +#include "../src/timezone.h" #include "../src/collation.h" #include "../src/rolecmds.h" #include "utils/fmgroids.h" @@ -49,14 +56,48 @@ #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 +#define SYSVARCHAR_MAX_LENGTH 4000 + +typedef enum +{ + OBJECT_TYPE_AGGREGATE_FUNCTION, + OBJECT_TYPE_CHECK_CONSTRAINT, + OBJECT_TYPE_DEFAULT_CONSTRAINT, + OBJECT_TYPE_FOREIGN_KEY_CONSTRAINT, + OBJECT_TYPE_TSQL_SCALAR_FUNCTION, + OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION, + OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION, + OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION, + OBJECT_TYPE_INTERNAL_TABLE, + OBJECT_TYPE_TSQL_STORED_PROCEDURE, + OBJECT_TYPE_ASSEMBLY_STORED_PROCEDURE, + OBJECT_TYPE_PLAN_GUIDE, + OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT, + OBJECT_TYPE_RULE, + OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE, + OBJECT_TYPE_SYSTEM_BASE_TABLE, + OBJECT_TYPE_SYNONYM, + OBJECT_TYPE_SEQUENCE_OBJECT, + OBJECT_TYPE_SERVICE_QUEUE, + OBJECT_TYPE_ASSEMBLY_DML_TRIGGER, + OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION, + OBJECT_TYPE_TSQL_DML_TRIGGER, + OBJECT_TYPE_TABLE_TYPE, + OBJECT_TYPE_TABLE, + OBJECT_TYPE_UNIQUE_CONSTRAINT, + OBJECT_TYPE_VIEW, + OBJECT_TYPE_EXTENDED_STORED_PROCEDURE +} ObjectPropertyType; + PG_FUNCTION_INFO_V1(trancount); PG_FUNCTION_INFO_V1(version); PG_FUNCTION_INFO_V1(error); PG_FUNCTION_INFO_V1(pgerror); PG_FUNCTION_INFO_V1(datalength); +PG_FUNCTION_INFO_V1(EOMONTH); PG_FUNCTION_INFO_V1(int_floor); PG_FUNCTION_INFO_V1(int_ceiling); PG_FUNCTION_INFO_V1(bit_floor); @@ -66,6 +107,7 @@ PG_FUNCTION_INFO_V1(servicename); PG_FUNCTION_INFO_V1(xact_state); PG_FUNCTION_INFO_V1(get_enr_list); PG_FUNCTION_INFO_V1(tsql_random); +PG_FUNCTION_INFO_V1(timezone_mapping); PG_FUNCTION_INFO_V1(is_member); PG_FUNCTION_INFO_V1(schema_id); PG_FUNCTION_INFO_V1(schema_name); @@ -75,15 +117,25 @@ 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); PG_FUNCTION_INFO_V1(has_dbaccess); PG_FUNCTION_INFO_V1(object_id); PG_FUNCTION_INFO_V1(object_name); +PG_FUNCTION_INFO_V1(type_id); +PG_FUNCTION_INFO_V1(type_name); PG_FUNCTION_INFO_V1(sp_datatype_info_helper); PG_FUNCTION_INFO_V1(language); +PG_FUNCTION_INFO_V1(identity_into_smallint); +PG_FUNCTION_INFO_V1(identity_into_int); +PG_FUNCTION_INFO_V1(identity_into_bigint); PG_FUNCTION_INFO_V1(host_name); +PG_FUNCTION_INFO_V1(host_id); +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); PG_FUNCTION_INFO_V1(bigint_degrees); @@ -98,15 +150,31 @@ PG_FUNCTION_INFO_V1(smallint_power); PG_FUNCTION_INFO_V1(numeric_degrees); PG_FUNCTION_INFO_V1(numeric_radians); PG_FUNCTION_INFO_V1(object_schema_name); +PG_FUNCTION_INFO_V1(parsename); 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); +PG_FUNCTION_INFO_V1(objectproperty_internal); +PG_FUNCTION_INFO_V1(sysutcdatetime); +PG_FUNCTION_INFO_V1(getutcdate); +PG_FUNCTION_INFO_V1(babelfish_concat_wrapper); +PG_FUNCTION_INFO_V1(getdate_internal); +PG_FUNCTION_INFO_V1(sysdatetime); +PG_FUNCTION_INFO_V1(sysdatetimeoffset); + +void *string_to_tsql_varchar(const char *input_str); +void *get_servername_internal(void); +void *get_servicename_internal(void); +void *get_language(void); +void *get_host_id(void); +int SPI_execute_raw_parsetree(RawStmt *parsetree, bool read_only, long tcount); +static HTAB *load_categories_hash(RawStmt *cats_sql, MemoryContext per_query_ctx); +static Tuplestorestate *get_bbf_pivot_tuplestore(RawStmt *sql, + HTAB *bbf_pivot_hash, + TupleDesc tupdesc, + bool randomAccess); extern bool canCommitTransaction(void); +extern bool is_ms_shipped(char *object_name, int type, Oid schema_id); -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; @@ -124,12 +192,132 @@ extern bool pltsql_xact_abort; extern bool pltsql_case_insensitive_identifiers; extern bool inited_ht_tsql_cast_info; extern bool inited_ht_tsql_datatype_precedence_info; +extern PLtsql_execstate *get_outermost_tsql_estate(int *nestlevel); -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 +#define MAX_CATNAME_LEN NAMEDATALEN +#define INIT_CATS 64 + +/* stored info for a bbf_pivot category */ +typedef struct bbf_pivot_cat_desc +{ + char *catname; /* full category name */ + uint64 attidx; /* zero based */ +} bbf_pivot_cat_desc; + +typedef struct bbf_pivot_hashent +{ + char internal_catname[MAX_CATNAME_LEN]; + bbf_pivot_cat_desc *catdesc; +} bbf_pivot_HashEnt; + +#define bbf_pivot_HashTableLookup(HASHTAB, CATNAME, CATDESC) \ +do { \ + bbf_pivot_HashEnt *hentry; char key[MAX_CATNAME_LEN]; \ + \ + MemSet(key, 0, MAX_CATNAME_LEN); \ + snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATNAME); \ + hentry = (bbf_pivot_HashEnt*) hash_search(HASHTAB, \ + key, HASH_FIND, NULL); \ + if (hentry) \ + CATDESC = hentry->catdesc; \ + else \ + CATDESC = NULL; \ +} while(0) + +#define bbf_pivot_HashTableInsert(HASHTAB, CATDESC) \ +do { \ + bbf_pivot_HashEnt *hentry; bool found; char key[MAX_CATNAME_LEN]; \ + \ + MemSet(key, 0, MAX_CATNAME_LEN); \ + snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATDESC->catname); \ + hentry = (bbf_pivot_HashEnt*) hash_search(HASHTAB, \ + key, HASH_ENTER, &found); \ + if (found) \ + ereport(ERROR, \ + (errcode(ERRCODE_DUPLICATE_OBJECT), \ + errmsg("duplicate category name"))); \ + hentry->catdesc = CATDESC; \ +} while(0) + +#define xpfree(var_) \ + do { \ + if (var_ != NULL) \ + { \ + pfree(var_); \ + var_ = NULL; \ + } \ + } while (0) + +#define xpstrdup(tgtvar_, srcvar_) \ + do { \ + if (srcvar_) \ + tgtvar_ = pstrdup(srcvar_); \ + else \ + tgtvar_ = NULL; \ + } while (0) + +#define xstreq(tgtvar_, srcvar_) \ + (((tgtvar_ == NULL) && (srcvar_ == NULL)) || \ + ((tgtvar_ != NULL) && (srcvar_ != NULL) && (strcmp(tgtvar_, srcvar_) == 0))) + + +Datum +babelfish_concat_wrapper(PG_FUNCTION_ARGS) +{ + text *arg1, *arg2, *new_text; + int32 arg1_size, arg2_size, new_text_size; + bool first_param = PG_ARGISNULL(0); + bool second_param = PG_ARGISNULL(1); + + if (pltsql_concat_null_yields_null) + { + if(first_param || second_param) + { + PG_RETURN_NULL(); // If any is NULL, return NULL + } + } + else + { + if (first_param && second_param) + { + PG_RETURN_NULL(); // If both are NULL, return NULL + } + else if (second_param) + { + PG_RETURN_TEXT_P(PG_GETARG_TEXT_PP(0)); // If only the second string is NULL, return the first string + } + else if (first_param) + { + PG_RETURN_TEXT_P(PG_GETARG_TEXT_PP(1)); // If only the first string is NULL, return the second string + } + } + arg1 = PG_GETARG_TEXT_PP(0); + arg2 = PG_GETARG_TEXT_PP(1); + arg1_size = VARSIZE_ANY_EXHDR(arg1); + arg2_size = VARSIZE_ANY_EXHDR(arg2); + + new_text_size = arg1_size + arg2_size + VARHDRSZ; + new_text = (text *) palloc(new_text_size); + + SET_VARSIZE(new_text, new_text_size); + + if(arg1_size>0) + { + memcpy(VARDATA(new_text), VARDATA_ANY(arg1), arg1_size); + } + if(arg2_size>0) + { + memcpy(VARDATA(new_text) + arg1_size, VARDATA_ANY(arg2), arg2_size); + } + + PG_RETURN_TEXT_P(new_text); +} + Datum trancount(PG_FUNCTION_ARGS) { @@ -152,22 +340,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" @@ -182,37 +371,75 @@ 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) +Datum sysutcdatetime(PG_FUNCTION_ARGS) +{ + PG_RETURN_TIMESTAMP(DirectFunctionCall2(timestamptz_zone,CStringGetTextDatum("UTC"), + PointerGetDatum(GetCurrentStatementStartTimestamp()))); + +} + +Datum getutcdate(PG_FUNCTION_ARGS) +{ + PG_RETURN_TIMESTAMP(DirectFunctionCall2(timestamp_trunc,CStringGetTextDatum("millisecond"),DirectFunctionCall2(timestamptz_zone,CStringGetTextDatum("UTC"), + PointerGetDatum(GetCurrentStatementStartTimestamp())))); + +} + +Datum getdate_internal(PG_FUNCTION_ARGS) +{ + PG_RETURN_TIMESTAMP(DirectFunctionCall2(timestamp_trunc,CStringGetTextDatum("millisecond"), + PointerGetDatum(GetCurrentStatementStartTimestamp()))); + +} + +Datum sysdatetime(PG_FUNCTION_ARGS) +{ + PG_RETURN_TIMESTAMPTZ(GetCurrentStatementStartTimestamp()); +} + +Datum sysdatetimeoffset(PG_FUNCTION_ARGS) +{ + + + PG_RETURN_POINTER((DirectFunctionCall1(common_utility_plugin_ptr->timestamp_datetimeoffset, + PointerGetDatum(GetCurrentStatementStartTimestamp())))); +} + +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); } /* @@ -236,14 +463,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)); } @@ -254,7 +482,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 */ @@ -276,7 +504,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) @@ -293,17 +521,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); } @@ -312,6 +541,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); } @@ -319,12 +549,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); } @@ -333,11 +564,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) { @@ -356,71 +589,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; + 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 */ + /* 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 */ @@ -433,11 +666,28 @@ tsql_random(PG_FUNCTION_ARGS) return result; } +Datum +timezone_mapping(PG_FUNCTION_ARGS) +{ + char *sqltmz = text_to_cstring(PG_GETARG_TEXT_P(0)); + VarChar *result = cstring_to_text("NULL"); + int len = (sizeof(win32_tzmap) / sizeof(*(win32_tzmap))); + for(int i=0;inspname; 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); @@ -493,37 +744,46 @@ schema_name(PG_FUNCTION_ARGS) Datum schema_id(PG_FUNCTION_ARGS) { - char *name; - char *input_name; - char *physical_name; - int id; + char *name = NULL; + 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 @@ -533,17 +793,19 @@ 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(); id = get_namespace_oid(physical_name, true); - pfree(name); + if (name) + pfree(name); pfree(physical_name); - - if(!OidIsValid(id)) + + if (!OidIsValid(id)) PG_RETURN_NULL(); PG_RETURN_INT32(id); @@ -559,80 +821,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(); } @@ -644,11 +912,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)) @@ -659,8 +928,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); @@ -681,7 +952,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) @@ -697,7 +968,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; @@ -705,13 +976,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) { @@ -726,8 +997,123 @@ 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 */ + 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 */ @@ -767,6 +1153,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,9 +1174,10 @@ 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)) - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - else continue; + (*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; /* If only a single backend was requested, and we found it, break. */ if (pid != -1) @@ -800,7 +1188,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; } @@ -811,7 +1199,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; @@ -819,13 +1207,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) { @@ -840,8 +1228,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 */ @@ -882,6 +1270,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; @@ -903,8 +1292,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) @@ -915,7 +1305,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; } @@ -931,52 +1321,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))); + /* + * 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); + pfree(buf.data); - PG_RETURN_INT32(result); + PG_RETURN_INT32(result); } /* @@ -990,25 +1381,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) { @@ -1027,12 +1421,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); @@ -1042,7 +1436,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); @@ -1065,7 +1459,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); @@ -1080,16 +1475,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(); } @@ -1100,7 +1499,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); } } @@ -1109,7 +1508,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 */ @@ -1117,37 +1519,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 @@ -1156,22 +1562,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); @@ -1182,21 +1589,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; @@ -1205,13 +1617,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); @@ -1225,7 +1638,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); } } @@ -1250,46 +1663,50 @@ 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; + text *result_text = 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 */ - enr = get_ENR_withoid(currentQueryEnv, object_id); - if(enr != NULL && enr->md.enrtype == ENR_TSQL_TEMP) + /* + * search in list of ENRs registered in the current query environment by + * object_id + */ + enr = get_ENR_withoid(currentQueryEnv, object_id, 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)); + PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(enr->md.name)); } /* search in pg_class by object_id */ @@ -1298,9 +1715,9 @@ 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); + result_text = cstring_to_text(NameStr(pg_class->relname)); // make a copy before releasing syscache schema_id = pg_class->relnamespace; } ReleaseSysCache(tuple); @@ -1317,7 +1734,7 @@ object_name(PG_FUNCTION_ARGS) if (pg_proc_aclcheck(object_id, user_id, ACL_EXECUTE) == ACLCHECK_OK) { Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple); - result = NameStr(procform->proname); + result_text = cstring_to_text(NameStr(procform->proname)); schema_id = procform->pronamespace; } ReleaseSysCache(tuple); @@ -1333,36 +1750,37 @@ 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); + result_text = cstring_to_text(NameStr(pg_type->typname)); } ReleaseSysCache(tuple); 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); + result_text = cstring_to_text(NameStr(pg_trigger->tgname)); schema_id = get_rel_namespace(pg_trigger->tgrelid); } found = true; @@ -1371,17 +1789,18 @@ 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); + { + result_text = cstring_to_text(NameStr(con->conname)); schema_id = con->connamespace; } ReleaseSysCache(tuple); @@ -1389,28 +1808,247 @@ 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_text) + { + /* + * 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))) - PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(result)); + 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 *) result_text); + } } PG_RETURN_NULL(); } +/* + * type_id + * Returns the object ID with type name as input. + * Returns NULL + * if input is NULL + * if there is no such type + * if user don't have right permission + * if any error occured + */ +Datum +type_id(PG_FUNCTION_ARGS) +{ + char *db_name, + *schema_name, + *object_name; + char *physical_schema_name; + char *input; + char **splitted_object_name; + Oid schema_oid = InvalidOid; + Oid user_id = GetUserId(); + Oid result = InvalidOid; + int i; + int len; + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + input = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + /* strip trailing whitespace from input */ + len = pg_mbstrlen(input); + i = len; + while (i > 0 && scanner_isspace((unsigned char) input[i - 1])) + i--; + if(i < len) + input[i] = '\0'; + + /* length should be restricted to 4000 */ + if (i > SYSVARCHAR_MAX_LENGTH) + ereport(ERROR, + (errcode(ERRCODE_STRING_DATA_LENGTH_MISMATCH), + errmsg("input value is too long for object name"))); + + /* resolve the two part name */ + splitted_object_name = split_object_name(input); + /* If three part name(db_name also included in input) then return null */ + if(pg_mbstrlen(splitted_object_name[1]) != 0) + { + pfree(input); + for (int i = 0; i < 4; i++) + pfree(splitted_object_name[i]); + pfree(splitted_object_name); + PG_RETURN_NULL(); + } + db_name = get_cur_db_name(); + schema_name = splitted_object_name[2]; + object_name = splitted_object_name[3]; + + /* 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); + for (int i = 0; i < 4; i++) + pfree(splitted_object_name[i]); + } + else + pfree(splitted_object_name[0]); + + pfree(input); + pfree(splitted_object_name); + + /* truncate identifiers if needed */ + truncate_tsql_identifier(db_name); + truncate_tsql_identifier(schema_name); + truncate_tsql_identifier(object_name); + + if (!strcmp(schema_name, "")) + { + // To check if it is a system datatype, search in typecode list and it will give result oid, else if not it will return null. + result = (*common_utility_plugin_ptr->get_tsql_datatype_oid) (object_name); + + // If null result, then it is not system datatype and now search with default schema in pg_type + if (!OidIsValid(result)) + { + /* 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); + PG_RETURN_NULL(); + } + else if ((guest_role_name && strcmp(user, guest_role_name) == 0)) + { + physical_schema_name = pstrdup(get_guest_schema_name(db_name)); + } + else + { + pfree(schema_name); + schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); + physical_schema_name = get_physical_schema_name(db_name, schema_name); + } + } + else + { + pfree(db_name); + pfree(schema_name); + pfree(object_name); + PG_RETURN_INT32(result); + } + } + else + { + // If schema is 'sys' or 'pg_catalog' then search in typecode list. + if(!strcmp(schema_name, "sys") || !strcmp(schema_name, "pg_catalog")) + { + result = (*common_utility_plugin_ptr->get_tsql_datatype_oid) (object_name); + pfree(db_name); + pfree(schema_name); + pfree(object_name); + if (OidIsValid(result)) + PG_RETURN_INT32(result); + else + PG_RETURN_NULL(); + } + else + { + 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 */ + if (physical_schema_name != NULL && pg_mbstrlen(physical_schema_name) != 0) + schema_oid = get_namespace_oid(physical_schema_name, true); + + pfree(schema_name); + pfree(db_name); + pfree(physical_schema_name); + + // Check if user has permission to access schema + if (OidIsValid(schema_oid) && pg_namespace_aclcheck(schema_oid, user_id, ACL_USAGE) == ACLCHECK_OK) + { + // Search in pg_type. + result = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(object_name), ObjectIdGetDatum(schema_oid)); + if (OidIsValid(result) && pg_type_aclcheck(result, user_id, ACL_USAGE) == ACLCHECK_OK) + { + pfree(object_name); + PG_RETURN_INT32(result); + } + } + pfree(object_name); + PG_RETURN_NULL(); +} + +/* + * type_name + * returns the type name with type id as input + * Returns NULL + * if there is no such type + * if user don't have right permission + */ +Datum +type_name(PG_FUNCTION_ARGS) +{ + Datum type_id = PG_GETARG_DATUM(0); + Datum tsql_typename; + HeapTuple tuple; + Oid user_id = GetUserId(); + char *result = NULL; + + LOCAL_FCINFO(fcinfo1, 1); + + if (type_id < 0) + PG_RETURN_NULL(); + + InitFunctionCallInfoData(*fcinfo1, NULL, 1, InvalidOid, NULL, NULL); + fcinfo1->args[0].value = type_id; + fcinfo1->args[0].isnull = false; + // Search in typecode list, it will return type name if system datatype, else will return null. + tsql_typename = (*common_utility_plugin_ptr->translate_pg_type_to_tsql) (fcinfo1); + if (tsql_typename) + { + PG_RETURN_TEXT_P(tsql_typename); + } + else + { + // Search in pg_type catalog + tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id)); + if (HeapTupleIsValid(tuple)) + { + if (pg_type_aclcheck(type_id, user_id, ACL_USAGE) == ACLCHECK_OK) + { + Form_pg_type pg_type = (Form_pg_type) GETSTRUCT(tuple); + result = NameStr(pg_type->typname); + } + ReleaseSysCache(tuple); + } + if (result) + { + PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text(result)); + } + } + PG_RETURN_NULL(); +} + 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; @@ -1427,20 +2065,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 @@ -1466,10 +2107,9 @@ 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 sys_varcharoid = get_sys_varcharoid(); + 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)) @@ -1649,6 +2289,72 @@ host_name(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } +Datum +host_id(PG_FUNCTION_ARGS) +{ + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->get_client_pid) { + char *host_id = psprintf("%d", (*pltsql_protocol_plugin_ptr)->get_client_pid()); + PG_RETURN_VARCHAR_P(string_to_tsql_varchar(host_id)); + } + else + PG_RETURN_NULL(); +} + +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; + + 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 (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)); + + PG_RETURN_VOID(); +} + +/** Added in 3_3_0, Deprecated in 3_4_0*/ +Datum +identity_into_smallint(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT16(0); +} + +/** Added in 3_3_0, Deprecated in 3_4_0*/ +Datum +identity_into_int(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT32(0); +} + +/** This function is only used for identifying IDENTITY() in SELECT-INTO statement, It is never actually invoked*/ +Datum +identity_into_bigint(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(0); +} + /* * Execute various integrity checks. * Returns true if all the checks pass otherwise @@ -1676,57 +2382,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); @@ -1738,202 +2447,435 @@ 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_trunc, + 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_trunc = DatumGetNumeric(DirectFunctionCall2(numeric_trunc, NumericGetDatum(result_numeric), Int32GetDatum(0))); + result = DatumGetInt64(DirectFunctionCall1(numeric_int8, NumericGetDatum(result_trunc))); - 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; - - arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int4_numeric,arg1)); + int32 arg1 = PG_GETARG_INT32(0); + Numeric arg2 = PG_GETARG_NUMERIC(1); + int32 result; + Numeric arg1_numeric, + result_trunc, + result_numeric; + + arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int4_numeric, arg1)); result_numeric = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(arg1_numeric), NumericGetDatum(arg2))); + result_trunc = DatumGetNumeric(DirectFunctionCall2(numeric_trunc, NumericGetDatum(result_numeric), Int32GetDatum(0))); + result = DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(result_trunc))); - 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; - - 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); + int16 arg1 = PG_GETARG_INT16(0); + Numeric arg2 = PG_GETARG_NUMERIC(1); + int32 result; + Numeric arg1_numeric, + result_numeric, + result_trunc; + + arg1_numeric = DatumGetNumeric(DirectFunctionCall1(int2_numeric, arg1)); + result_numeric = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(arg1_numeric), NumericGetDatum(arg2))); + result_trunc = DatumGetNumeric(DirectFunctionCall2(numeric_trunc, NumericGetDatum(result_numeric), Int32GetDatum(0))); + result = DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(result_trunc))); + 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))); PG_RETURN_NUMERIC(result); } -/* Returns the database schema name for schema-scoped objects. */ +/* +* The PARSENAME() function in T-SQL is used to parse a string representing a four-part SQL Server object name, such as "database.schema.object.column". +* If we have an a single '[' ,']' or '"' its a syntax error. +* If object_name is inside brackets like [object_name] its should still return object_name without printing brackets. +* If object_name is inside double quotes like "object_name" its should still return object_name without printing double quotes. +*/ Datum -object_schema_name(PG_FUNCTION_ARGS) +parsename(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; + text *object_name = PG_GETARG_TEXT_PP(0); + int object_piece = PG_GETARG_INT32(1); + char *object_name_str = text_to_cstring(object_name); + int len = strlen(object_name_str); + typedef enum + { + STATE_INITIAL, + STATE_DEFAULT, + STATE_IN_QUOTES, + STATE_IN_BRACKETS + } State; + State initial_state[4] = {STATE_INITIAL}; + State state = STATE_DEFAULT; + int consumed; + int32_t code; + int total_chars = 0; + int total_length = 0; + char c; + char *start_positions[4] = {NULL}; + char *end_positions[4] = {NULL}; + // int initial_state[4] = {0}; + int current_part = 0; + text *result; + start_positions[current_part] = object_name_str; + + // object_piece should only have maximum of 4 parts. + if (object_piece < 1 || object_piece > 4) + { + PG_RETURN_NULL(); + } - if(PG_ARGISNULL(0)) - PG_RETURN_NULL(); - else - object_id = (Oid) PG_GETARG_INT32(0); + for (int i = 0; i < len;) + { + code = (*common_utility_plugin_ptr->GetUTF8CodePoint)((const unsigned char *)&object_name_str[i], len - i, &consumed); + c = object_name_str[i]; + if (total_chars > 128 || total_length > 256) + { + PG_RETURN_NULL(); + } - if(PG_ARGISNULL(1)) - database_id = get_cur_db_id(); - else { - database_id = (Oid) PG_GETARG_INT32(1); - user_id = GetSessionUserId(); - } + if (state == STATE_DEFAULT) + { + if (c == '"') + { + if (total_chars > 0) + { + PG_RETURN_NULL(); + } - /* 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) - namespace_oid = temp_nspid; - else - PG_RETURN_NULL(); - } - 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 (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 */ - /* Lookup namespace_oid in pg_trigger */ - temp_nspid = tsql_get_trigger_rel_oid(object_id); - 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 - */ - if (pg_class_aclcheck(temp_nspid, user_id, ACL_SELECT) == ACLCHECK_OK) - namespace_oid = get_rel_namespace(temp_nspid); - else - PG_RETURN_NULL(); - } - } - 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); - } + state = STATE_IN_QUOTES; + // save the initial state so that we can escape the correct characters at the end. + if (initial_state[current_part] == STATE_INITIAL) + { + initial_state[current_part] = STATE_IN_QUOTES; + } - /* Find schema name from 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 != get_dbid_from_physical_schema_name(namespace_name, true)) - PG_RETURN_NULL(); - schema_name = get_logical_schema_name(namespace_name, true); - pfree(namespace_name); - PG_RETURN_TEXT_P(cstring_to_text(schema_name)); - } - else - PG_RETURN_NULL(); -} + start_positions[current_part] = &object_name_str[i + 1]; + i += consumed; + continue; + } + else if(c == ']') + { + PG_RETURN_NULL(); + } + else if (c == '[') + { + if (total_chars > 0) + { + PG_RETURN_NULL(); + } -Datum -pg_extension_config_remove(PG_FUNCTION_ARGS) -{ - Oid tableoid = PG_GETARG_OID(0); - char *tablename = get_rel_name(tableoid); + state = STATE_IN_BRACKETS; + if (initial_state[current_part] == STATE_INITIAL) + { + initial_state[current_part] = STATE_IN_BRACKETS; + } - /* - * We only allow this to be called from an extension's SQL script. We + start_positions[current_part] = &object_name_str[i + 1]; + i += consumed; + continue; + } + else if (c == '.') + { + // do not update the value of end_positions[current_part] if there is already a value in end_postions[current_part] & previous character is " or ]. + if ( !((end_positions[current_part] != NULL) && (object_name_str[i - 1] == '"')) && !((end_positions[current_part] != NULL) && (object_name_str[i - 1] == ']')) ) + { + end_positions[current_part] = &object_name_str[i - 1]; + } + + current_part++; + if (current_part > 3) + { + PG_RETURN_NULL(); + } + + start_positions[current_part] = &object_name_str[i + 1]; + total_chars = 0; + total_length = 0; + } + } + else if (state == STATE_IN_QUOTES) + { + if (c == '"') + { + // is there a next character and is it double quotes? + if (i + consumed < len && object_name_str[i + consumed] == '"') + { + i += consumed; + } + else + { + state = STATE_DEFAULT; + end_positions[current_part] = &object_name_str[i - 1]; + if (i + 1 < len && object_name_str[i + 1] != '.') + { + PG_RETURN_NULL(); + } + i += consumed; + continue; + } + } + } + else if (state == STATE_IN_BRACKETS) + { + if (c == ']') + { + // is there a next character and if it is there, is it closing brace? + if (i + consumed < len && object_name_str[i + consumed] == ']') + { + i += consumed; + } + else + { + state = STATE_DEFAULT; + end_positions[current_part] = &object_name_str[i - 1]; + if (i + 1 < len && object_name_str[i + 1] != '.') + { + PG_RETURN_NULL(); + } + i += consumed; + continue; + } + } + } + + // This line increments total_chars by 1 if the current character's Unicode code point is less than or equal to 0xFFFF (i.e., it can be represented in UTF-16), and by 2 otherwise. + if (state > STATE_DEFAULT || (state == STATE_DEFAULT && c != '.')) + { + if (code <= 0xFFFF) + total_chars += 1; + else + total_chars += 2; + total_length += (code <= 0xFFFF) ? 2 : 4; + } + i += consumed; + } + + if (state != STATE_DEFAULT) + { + PG_RETURN_NULL(); + } + + if (total_chars > 128 || total_length > 256) + { + PG_RETURN_NULL(); + } + + // if there is only 1 part and no '.', set the end position to length-1. + if (end_positions[current_part] == NULL) + { + end_positions[current_part] = &object_name_str[len - 1]; + } + + // Reverse the object piece index + object_piece = current_part + 1 - object_piece; + if (object_piece < 0 || object_piece > current_part) + { + PG_RETURN_NULL(); + } + + if (object_piece >= 0 && object_piece <= current_part) + { + int part_length = end_positions[object_piece] - start_positions[object_piece] + 1; + if (part_length > 0) + { + char *part = (char*) palloc(part_length + 1); // Allocate memory for part string + int part_index = 0; + for (int j = 0; j < part_length; j++) + { + // Copy part string with handling of escaped double quotes and closing brackets and checking initial state. + if ( (initial_state[object_piece] == STATE_IN_QUOTES && start_positions[object_piece][j] == '"' && start_positions[object_piece][j + 1] == '"') || + (initial_state[object_piece] == STATE_IN_BRACKETS && start_positions[object_piece][j] == ']' && start_positions[object_piece][j + 1] == ']')) + { + part[part_index++] = start_positions[object_piece][j++]; + } + else + { + part[part_index++] = start_positions[object_piece][j]; + } + } + part[part_index] = '\0'; // Null-terminate part string + result = cstring_to_text(part); + pfree(part); // Free part string memory + PG_RETURN_TEXT_P(result); + } + } + + PG_RETURN_NULL(); +} + +/* Returns the database schema name for schema-scoped objects. */ +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)) + PG_RETURN_NULL(); + else + object_id = (Oid) PG_GETARG_INT32(0); + + if (PG_ARGISNULL(1)) + database_id = get_cur_db_id(); + 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) + namespace_oid = temp_nspid; + else + PG_RETURN_NULL(); + } + 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 (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 */ + /* Lookup namespace_oid in pg_trigger */ + temp_nspid = tsql_get_trigger_rel_oid(object_id); + 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 + */ + if (pg_class_aclcheck(temp_nspid, user_id, ACL_SELECT) == ACLCHECK_OK) + namespace_oid = get_rel_namespace(temp_nspid); + else + PG_RETURN_NULL(); + } + } + 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)) + { + 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 != get_dbid_from_physical_schema_name(namespace_name, true)) + PG_RETURN_NULL(); + schema_name = get_logical_schema_name(namespace_name, true); + pfree(namespace_name); + PG_RETURN_TEXT_P(cstring_to_text(schema_name)); + } + else + PG_RETURN_NULL(); +} + +Datum +pg_extension_config_remove(PG_FUNCTION_ARGS) +{ + 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 * shouldn't need any permissions check beyond that. */ if (!creating_extension) @@ -1951,8 +2893,1281 @@ 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(); } + +/* + * The EOMONTH function is a Transact-SQL function in SQL Server that returns + * the last day of the month of a specified date, with an optional offset. + */ +Datum +EOMONTH(PG_FUNCTION_ARGS) +{ + int year, month, day; + int offset = 0; + DateADT date; + bool isOffsetGiven = false; + bool isOriginalDateOutsideTSQLEndLimit = false; + + if (PG_ARGISNULL(0)) + { + PG_RETURN_NULL(); + } + else + { + date = PG_GETARG_DATEADT(0); + } + + if (!PG_ARGISNULL(1)) + { + offset = PG_GETARG_INT32(1); + isOffsetGiven = true; + } + + /* Convert the date to year, month, day */ + j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day); + + /* This flag is required later to check and throw the T-SQL compatibility error. */ + isOriginalDateOutsideTSQLEndLimit = year < 1 || year > 9999; + + /* Adjust the month based on the offset */ + month += offset; + + /* + * Check if the new month is greater than 0, which indicates a positive offset. + * If it is true, the months continue to increase one by one, until they reach 12. After this point, they revert back to 1 and + * if the months exceed 12, it signifies that we must also increment the year. + * + * If it is false, the months continue to decrease one by one, until they reach 1. After this point, they will reset to 12 and + * if the months go below 1, it signifies that we must also decrement the year. + */ + if(month > 0) + { + /* + * The year value is incremented by how many full sets of 12 months fit into the 'month' value. + * Subtracting 1 from 'month' before dividing ensures we don't count an extra year when 'month' is exactly divisible by 12. + * We are considering 12 months as a full year, so if we have exactly 12 months, we should not increment the year yet. + */ + year += (month - 1) / 12; + + /* + * The new month value is calculated based on the remainder when divided by 12. + * This makes sure the month value stays within the range of 1 to 12. The subtraction by 1 and addition by 1 + * ensure that the month value starts from 1 (January) rather than 0. + */ + month = (month - 1) % 12 + 1; + } + else + { + /* + * The year value is decremented based on how many full sets of 12 months fit into the 'month' value. + * This calculates how many years to decrement given the total number of negative months. + */ + year += month / 12 - 1; + + /* + * The new month value is calculated based on the modulus operation when divided by 12. + * If the month value is negative, this operation makes sure the month value stays within the range of 1 to 12. + */ + month = month % 12 + 12; + } + + /* Now move to the first day of the next month */ + month++; + + /* If the new year is less than 1 or greater than 9999, report an error. */ + if (year < 1 || year > 9999) + { + /* If the offset was given by the user and the provided year was within T-SQL range, throw overflow error else throw T-SQL compatibility error. */ + if (isOffsetGiven && !isOriginalDateOutsideTSQLEndLimit) + { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), + errmsg("Adding a value to a 'date' column caused an overflow."))); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), + errmsg("The date exceeds T-SQL compatibility limits."))); + } + } + + /* + * Convert the year, month, and day (1st day of the new month) back date format, then subtract one day + * to get the last day of the "offset" month. + */ + date = date2j(year, month, 1) - POSTGRES_EPOCH_JDATE - 1; + PG_RETURN_DATEADT(date); +} + +/* + * Funtion used to check whether the object is MS shipped. + * This is being used in objectproperty_internal. + */ +bool is_ms_shipped(char *object_name, int type, Oid schema_id) +{ + int i = 0; + bool is_ms_shipped = false; + char *namespace_name = NULL; + /* + * This array contains information of objects that reside in a schema in one specfic database. + * For example, 'master_dbo' schema can only exist in the 'master' database. + */ +#define NUM_DB_OBJECTS 11 + int shipped_objects_not_in_sys_db_type[NUM_DB_OBJECTS] = { + OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_TSQL_STORED_PROCEDURE, + OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_TSQL_STORED_PROCEDURE, + OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_TSQL_STORED_PROCEDURE, + OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_TSQL_SCALAR_FUNCTION, + OBJECT_TYPE_VIEW, OBJECT_TYPE_VIEW, OBJECT_TYPE_TSQL_STORED_PROCEDURE + }; + char *shipped_objects_not_in_sys_db[NUM_DB_OBJECTS][2] = { + {"xp_qv","master_dbo"}, + {"xp_instance_regread","master_dbo"}, + {"sp_addlinkedserver", "master_dbo"}, + {"sp_addlinkedsrvlogin", "master_dbo"}, + {"sp_dropserver", "master_dbo"}, + {"sp_droplinkedsrvlogin", "master_dbo"}, + {"sp_testlinkedserver", "master_dbo"}, + {"fn_syspolicy_is_automation_enabled", "msdb_dbo"}, + {"syspolicy_configuration", "msdb_dbo"}, + {"syspolicy_system_health_state", "msdb_dbo"}, + {"sp_enum_oledb_providers", "master_dbo"} + }; + + /* + * This array contains information of objects that reside in a schema in any number of databases. + * For example, 'dbo' schema can exist in the 'master', 'tempdb', 'msdb', and any user created database. + */ +#define NUM_ALL_DB_OBJECTS 1 + int shipped_objects_not_in_sys_all_db_type[NUM_ALL_DB_OBJECTS] = {OBJECT_TYPE_VIEW}; + char *shipped_objects_not_in_sys_all_db[NUM_ALL_DB_OBJECTS][2] = { + {"sysdatabases","dbo"} + }; + + Relation rel; + HeapTuple tuple; + ScanKeyData scanKey; + SysScanDesc scan; + Datum datum; + TupleDesc dsc; + + + namespace_name = get_namespace_name(schema_id); + + if (pg_strcasecmp(namespace_name, "sys") == 0) + is_ms_shipped = true; + + + /* + * Check whether the object is present in shipped_objects_not_in_sys_db. + */ + for (i = 0; i < NUM_DB_OBJECTS; i++) + { + if (is_ms_shipped || (type == shipped_objects_not_in_sys_db_type[i] && + pg_strcasecmp(object_name, shipped_objects_not_in_sys_db[i][0]) == 0 && + pg_strcasecmp(namespace_name, shipped_objects_not_in_sys_db[i][1]) == 0)) + { + is_ms_shipped = true; + break; + } + } +#undef NUM_DB_OBJECTS + + rel = table_open(namespace_ext_oid, AccessShareLock); + dsc = RelationGetDescr(rel); + + /* + * Check whether the object is present in shipped_objects_not_in_sys_all_db. + * + * As the objects in shipped_objects_not_in_sys_all_db can be present in any number of databases, + * We scan the pg_namespace catalog to find the occurences in all the databases and find whether + * any entry matches the object that we are looking for. + */ + for (i = 0; i < NUM_ALL_DB_OBJECTS; i++) + { + char *tempnspname = NULL; + bool isNull = false; + + if (is_ms_shipped) + break; + if (type != shipped_objects_not_in_sys_all_db_type[i]) + continue; + + ScanKeyInit(&scanKey, + Anum_namespace_ext_orig_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(shipped_objects_not_in_sys_all_db[i][1])); + + scan = systable_beginscan(rel, InvalidOid, false, + NULL, 1, &scanKey); + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + datum = heap_getattr(tuple, Anum_namespace_ext_namespace, dsc, &isNull); + tempnspname = TextDatumGetCString(datum); + if (pg_strcasecmp(namespace_name, tempnspname) == 0) + { + is_ms_shipped = true; + break; + } + } + + systable_endscan(scan); + if (tempnspname) + pfree(tempnspname); + } +#undef NUM_ALL_DB_OBJECTS + + table_close(rel, AccessShareLock); + + return is_ms_shipped; +} + +Datum +objectproperty_internal(PG_FUNCTION_ARGS) +{ + Oid object_id; + Oid schema_id = InvalidOid; + char *property; + Oid user_id = GetUserId(); + HeapTuple tuple; + int type = 0; + char *object_name = NULL; + char *nspname = NULL; + + if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) + PG_RETURN_NULL(); + else + { + object_id = (Oid) PG_GETARG_INT32(0); + property = text_to_cstring(PG_GETARG_TEXT_P(1)); + property = downcase_identifier(property, strlen(property), false, true); + remove_trailing_spaces(property); + } + + /* + * Search for the object_id in pg_class, pg_proc, pg_attrdef, pg_constraint. + * If the object_id is not found in any of the above catalogs, return NULL. + * Else, get the object name, type of the object and the schema_id in which + * the object is present. + */ + + /* pg_class */ + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)) + { + Form_pg_class pg_class = (Form_pg_class) GETSTRUCT(tuple); + + object_name = NameStr(pg_class->relname); + + if (pg_class_aclcheck(object_id, user_id, ACL_SELECT) == ACLCHECK_OK) + schema_id = get_rel_namespace(object_id); + + /* + * Get the type of the object + */ + if ((pg_class->relpersistence == 'p' || pg_class->relpersistence == 'u' || pg_class->relpersistence == 't') && + (pg_class->relkind == 'r')) + { + /* + * Check whether it is a Table type (TT) object. + * The reltype of the pg_class object should be there in pg_type. The pg_type object found + * should be of composite type (c) and the type of dependency should be DEPENDENCY_INTERNAL (i). + * We scan pg_depend catalog to find the type of the dependency. + */ + HeapTuple tp; + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(pg_class->reltype)); + if(HeapTupleIsValid(tp)) + { + Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp); + + if (typform->typtype == 'c') + { + Relation depRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + depRel = table_open(DependRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(typform->typrelid)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(typform->oid)); + + scan = systable_beginscan(depRel, InvalidOid, false, + NULL, 2, key); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); + + if (depform->deptype == 'i') + type = OBJECT_TYPE_TABLE_TYPE; + } + + systable_endscan(scan); + + table_close(depRel, RowExclusiveLock); + } + ReleaseSysCache(tp); + } + /* + * If the object is not of Table type (TT), it should be user defined table (U) + */ + if (type == 0 || type != OBJECT_TYPE_TABLE_TYPE) + type = OBJECT_TYPE_TABLE; + } + else if (pg_class->relkind == 'v') + type = OBJECT_TYPE_VIEW; + else if (pg_class->relkind == 's') + type = OBJECT_TYPE_SEQUENCE_OBJECT; + + ReleaseSysCache(tuple); + } + /* pg_proc */ + if (!schema_id) + { + tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)) + { + if (pg_proc_aclcheck(object_id, user_id, ACL_EXECUTE) == ACLCHECK_OK) + { + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple); + + object_name = NameStr(procform->proname); + + schema_id = tsql_get_proc_nsp_oid(object_id); + + if (procform->prokind == 'p') + type = OBJECT_TYPE_TSQL_STORED_PROCEDURE; + else if (procform->prokind == 'a') + type = OBJECT_TYPE_AGGREGATE_FUNCTION; + else + { + /* + * Check whether the object is SQL DML trigger(TR), SQL table-valued-function (TF), + * SQL inline table-valued function (IF), SQL scalar function (FN). + */ + char *temp = format_type_extended(procform->prorettype, -1, FORMAT_TYPE_ALLOW_INVALID); + /* + * If the prorettype of the pg_proc object is "trigger", then the type of the object is "TR" + */ + if (pg_strcasecmp(temp, "trigger") == 0) + type = OBJECT_TYPE_TSQL_DML_TRIGGER; + /* + * For SQL table-valued-functions and SQL inline table-valued functions, re-implement the existing SQL. + */ + else if (procform->proretset) + { + HeapTuple tp; + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procform->prorettype)); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typeform = (Form_pg_type) GETSTRUCT(tuple); + + if (typeform->typtype == 'c') + type = OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION; + else + type = OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION; + + ReleaseSysCache(tp); + } + } + else + type = OBJECT_TYPE_TSQL_SCALAR_FUNCTION; + + pfree(temp); + } + } + ReleaseSysCache(tuple); + } + } + /* pg_attrdef */ + if (!schema_id) + { + Relation attrdefrel; + ScanKeyData key; + SysScanDesc attrscan; + + attrdefrel = table_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&key, + Anum_pg_attrdef_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object_id)); + + attrscan = systable_beginscan(attrdefrel, AttrDefaultOidIndexId, true, + NULL, 1, &key); + + tuple = systable_getnext(attrscan); + if (HeapTupleIsValid(tuple)) + { + /* + * scan pg_attribute catalog to find the corresponding row. + * This pg_attribute pbject will be helpful to check whether the object is DEFAULT (D) + * and to find the schema_id. + */ + Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tuple); + Relation attrRel; + ScanKeyData key[2]; + SysScanDesc scan; + HeapTuple tup; + + if (pg_attribute_aclmask(atdform->adrelid, atdform->adnum, user_id, ACL_SELECT, ACLMASK_ANY) == ACLCHECK_OK && + pg_attribute_aclmask(atdform->adrelid, atdform->adnum, user_id, ACL_INSERT, ACLMASK_ANY) == ACLCHECK_OK && + pg_attribute_aclmask(atdform->adrelid, atdform->adnum, user_id, ACL_UPDATE, ACLMASK_ANY) == ACLCHECK_OK && + pg_attribute_aclmask(atdform->adrelid, atdform->adnum, user_id, ACL_REFERENCES, ACLMASK_ANY) == ACLCHECK_OK) + { + attrRel = table_open(AttributeRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_attribute_attrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(atdform->adrelid)); + ScanKeyInit(&key[1], + Anum_pg_attribute_attnum, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(atdform->adnum)); + + scan = systable_beginscan(attrRel, AttributeRelidNumIndexId, true, + NULL, 2, key); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_attribute attrform = (Form_pg_attribute) GETSTRUCT(tup); + + if (attrform->atthasdef && !attrform->attgenerated) + { + object_name = NameStr(attrform->attname); + type = OBJECT_TYPE_DEFAULT_CONSTRAINT; + if (pg_class_aclcheck(atdform->adrelid, user_id, ACL_SELECT) == ACLCHECK_OK) + schema_id = get_rel_namespace(atdform->adrelid); + } + } + + systable_endscan(scan); + + table_close(attrRel, RowExclusiveLock); + } + + } + systable_endscan(attrscan); + table_close(attrdefrel, AccessShareLock); + } + /* pg_constraint */ + if (!schema_id) + { + tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(object_id)); + if (HeapTupleIsValid(tuple)) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + object_name = NameStr(con->conname); + schema_id = tsql_get_constraint_nsp_oid(object_id, user_id); + /* + * If the contype is 'f' on the pg_constraint object, then it is a Foreign key constraint + */ + if (con->contype == 'f') + type = OBJECT_TYPE_FOREIGN_KEY_CONSTRAINT; + /* + * If the contype is 'p' on the pg_constraint object, then it is a Primary key constraint + */ + else if (con->contype == 'p') + type = OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT; + /* + * Reimplemented the existing SQL . + * If the contype is 'c' and conrelid is 0 on the pg_constraint object, then it is a Check constraint + */ + else if (con->contype == 'c' && con->conrelid != 0) + type = OBJECT_TYPE_CHECK_CONSTRAINT; + + ReleaseSysCache(tuple); + } + } + + /* + * If the object_id is not found or user does not have enough privileges on the object and schema, + * Return NULL. + */ + if (!schema_id || pg_namespace_aclcheck(schema_id, user_id, ACL_USAGE) != ACLCHECK_OK) + { + pfree(property); + PG_RETURN_NULL(); + } + + /* + * schema_id found should be in sys.schemas view except 'sys'. + */ + nspname = get_namespace_name(schema_id); + + if (!(nspname && pg_strcasecmp(nspname, "sys") == 0) && + (!nspname || pg_strcasecmp(nspname, "pg_catalog") == 0 || + pg_strcasecmp(nspname, "pg_toast") == 0 || + pg_strcasecmp(nspname, "public") == 0)) + { + pfree(property); + if (nspname) + pfree(nspname); + + PG_RETURN_NULL(); + } + + pfree(nspname); + + /* OwnerId */ + if (pg_strcasecmp(property, "ownerid") == 0) + { + /* + * Search for schema_id in pg_namespace catalog. Return nspowner from + * the found pg_namespace object. + */ + if (OidIsValid(schema_id)) + { + HeapTuple tp; + int result; + + tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(schema_id)); + if (HeapTupleIsValid(tp)) + { + Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp); + result = ((int) nsptup->nspowner); + ReleaseSysCache(tp); + } + else + { + pfree(property); + PG_RETURN_NULL(); + } + pfree(property); + PG_RETURN_INT32(result); + } + } + /* IsDefaultCnst */ + else if (pg_strcasecmp(property, "isdefaultcnst") == 0) + { + /* + * The type of the object should be OBJECT_TYPE_DEFAULT_CONSTRAINT. + */ + if (type == OBJECT_TYPE_DEFAULT_CONSTRAINT) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* ExecIsQuotedIdentOn, IsSchemaBound, ExecIsAnsiNullsOn */ + else if (pg_strcasecmp(property, "execisquotedidenton") == 0 || + pg_strcasecmp(property, "isschemabound") == 0 || + pg_strcasecmp(property, "execisansinullson") == 0) + { + /* + * These properties are only applicable to OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE, + * OBJECT_TYPE_VIEW, OBJECT_TYPE_TSQL_DML_TRIGGER, OBJECT_TYPE_TSQL_SCALAR_FUNCTION, OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION, + * OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION and OBJECT_TYPE_RULE. + * Hence, return NULL if the object is not from the above types. + */ + if (!(type == OBJECT_TYPE_TSQL_STORED_PROCEDURE || type == OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE || + type == OBJECT_TYPE_VIEW || type == OBJECT_TYPE_TSQL_DML_TRIGGER || type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || + type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION || + type == OBJECT_TYPE_RULE)) + { + pfree(property); + PG_RETURN_NULL(); + } + + /* + * Currently, for IsSchemaBound property, we have hardcoded the value to 0 + */ + if (pg_strcasecmp(property, "isschemabound") == 0) + { + pfree(property); + PG_RETURN_INT32(0); + } + /* + * For ExecIsQuotedIdentOn and ExecIsAnsiNullsOn, we hardcoded it to 1 + */ + pfree(property); + PG_RETURN_INT32(1); + } + /* TableFullTextPopulateStatus, TableHasVarDecimalStorageFormat */ + else if (pg_strcasecmp(property, "tablefulltextpopulatestatus") == 0 || + pg_strcasecmp(property, "tablehasvardecimalstorageformat") == 0) + { + /* + * Currently, we have hardcoded the return value to 0. + */ + if (type == OBJECT_TYPE_TABLE) + { + pfree(property); + PG_RETURN_INT32(0); + } + /* + * These properties are only applicable if the type of the object is TABLE, + * Hence, return NULL if the object is not a TABLE. + */ + pfree(property); + PG_RETURN_NULL(); + } + /* IsMSShipped*/ + else if (pg_strcasecmp(property, "ismsshipped") == 0) + { + /* + * Check whether the object is MS shipped. We are using is_ms_shipped helper function + * to check the same. + */ + if (is_ms_shipped(object_name, type, schema_id)) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsDeterministic */ + else if (pg_strcasecmp(property, "isdeterministic") == 0) + { + /* + * Currently, we hardcoded the value to 0. + */ + pfree(property); + PG_RETURN_INT32(0); + } + /* IsProcedure */ + else if (pg_strcasecmp(property, "isprocedure") == 0) + { + /* + * Check whether the type of the object is OBJECT_TYPE_TSQL_STORED_PROCEDURE. + */ + if (type == OBJECT_TYPE_TSQL_STORED_PROCEDURE) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsTable */ + else if (pg_strcasecmp(property, "istable") == 0) + { + /* + * The type of the object should be OBJECT_TYPE_INTERNAL_TABLE or OBJECT_TYPE_TABLE_TYPE or + * TABLE or OBJECT_TYPE_SYSTEM_BASE_TABLE. + */ + if (type == OBJECT_TYPE_INTERNAL_TABLE || type == OBJECT_TYPE_TABLE_TYPE || + type == OBJECT_TYPE_TABLE || type == OBJECT_TYPE_SYSTEM_BASE_TABLE) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsView */ + else if (pg_strcasecmp(property, "isview") == 0) + { + /* + * The type of the object should be OBJECT_TYPE_VIEW. + */ + if (type == OBJECT_TYPE_VIEW) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsUserView */ + else if (pg_strcasecmp(property, "isusertable") == 0) + { + /* + * The object should be of the type TABLE and should not be MS shipped. + */ + if (type == OBJECT_TYPE_TABLE && is_ms_shipped(object_name, type, schema_id) == 0) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsTableFunction */ + else if (pg_strcasecmp(property, "istablefunction") == 0) + { + /* + * The object should be OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION or OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION + * OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION. + */ + if (type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION || + type == OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsInlineFunction */ + else if (pg_strcasecmp(property, "isinlinefunction") == 0) + { + /* + * The object should be OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION. + */ + if (type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + + } + /* IsScalarFunction */ + else if (pg_strcasecmp(property, "isscalarfunction") == 0) + { + /* + * The object should be either OBJECT_TYPE_TSQL_SCALAR_FUNCTION or OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION. + */ + if (type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsPrimaryKey */ + else if (pg_strcasecmp(property, "isprimarykey") == 0) + { + /* + * The object should be a OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT. + */ + if (type == OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + /* IsIndexed */ + else if (pg_strcasecmp(property, "isindexed") == 0) + { + /* + * Search for object_id in pg_index catalog by indrelid column. + * The object is indexed if the entry exists in pg_index. + */ + Relation indRel; + ScanKeyData key; + SysScanDesc scan; + HeapTuple tup; + + if (type != OBJECT_TYPE_TABLE) + PG_RETURN_INT32(0); + + indRel = table_open(IndexRelationId, RowExclusiveLock); + + ScanKeyInit(&key, + Anum_pg_index_indrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object_id)); + + scan = systable_beginscan(indRel, IndexIndrelidIndexId, true, + NULL, 1, &key); + + if (HeapTupleIsValid(tup = systable_getnext(scan))) + { + systable_endscan(scan); + table_close(indRel, RowExclusiveLock); + pfree(property); + PG_RETURN_INT32(1); + } + + systable_endscan(scan); + table_close(indRel, RowExclusiveLock); + pfree(property); + + PG_RETURN_INT32(0); + } + /* IsDefault */ + else if (pg_strcasecmp(property, "isdefault") == 0) + { + /* + * Currently hardcoded to 0. + */ + pfree(property); + PG_RETURN_INT32(0); + } + /* IsOBJECT_TYPE_RULE */ + else if (pg_strcasecmp(property, "isrule") == 0) + { + /* + * Currently hardcoded to 0. + */ + pfree(property); + PG_RETURN_INT32(0); + } + /* IsTrigger */ + else if (pg_strcasecmp(property, "istrigger") == 0) + { + /* + * The type of the object should be OBJECT_TYPE_ASSEMBLY_DML_TRIGGER. + */ + if (type == OBJECT_TYPE_ASSEMBLY_DML_TRIGGER) + { + pfree(property); + PG_RETURN_INT32(1); + } + pfree(property); + PG_RETURN_INT32(0); + } + + if (property) + pfree(property); + + PG_RETURN_NULL(); +} + +/* +* We transformed tsql pivot stmt to 3 parsetree. The outer parsetree is a wrapper stmt +* while the other two are helper stmts. Since postgres does not natively support execute +* raw parsetree, and we can only get raw parsetree after the analyzer, we created this +* SPI function to help execute raw parsetree. +*/ +int +SPI_execute_raw_parsetree(RawStmt *parsetree, bool read_only, long tcount) +{ + _SPI_plan plan; + int ret; + List *plancache_list; + CachedPlanSource *plansource; + int prev_sql_dialect; + + if (parsetree == NULL || tcount < 0) + return SPI_ERROR_ARGUMENT; + + /* + * set sql_dialect to tsql, which is needed for raw parsetree parsing + * and processing + */ + prev_sql_dialect = sql_dialect; + sql_dialect = SQL_DIALECT_TSQL; + + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; + plan.cursor_options = CURSOR_OPT_PARALLEL_OK; + + /* + * Construct plancache entries, but don't do parse analysis yet. + */ + plancache_list = NIL; + + /* + * src sql can be optained from pstate->p_sourcetext, but + * it is not important here + */ + plansource = CreateOneShotCachedPlan(parsetree, + "SQL NOT AVAILABLE", + CreateCommandTag(parsetree->stmt)); + + plancache_list = lappend(plancache_list, plansource); + plan.plancache_list = plancache_list; + plan.oneshot = true; + PG_TRY(); + { + ret = SPI_execute_plan_with_paramlist(&plan, NULL, read_only, tcount); + } + PG_FINALLY(); + { + /* reset sql_dialect */ + sql_dialect = prev_sql_dialect; + } + PG_END_TRY(); + + return ret; +} + +PG_FUNCTION_INFO_V1(bbf_pivot); +Datum +bbf_pivot(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + HTAB *bbf_pivot_hash; + + MemoryContext tsql_outmost_context; + PLtsql_execstate *tsql_outmost_estat; + RawStmt *bbf_pivot_src_sql; + RawStmt *bbf_pivot_cat_sql; + int nestlevel; + List *per_pivot_list; + + + /* 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) || + rsinfo->expectedDesc == NULL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not allowed in this context"))); + + /* + * Previously we saved two raw parsetrees in tsql outermost context + * here we are retrieve those raw parsetree for pivot execution + */ + tsql_outmost_estat = get_outermost_tsql_estate(&nestlevel); + tsql_outmost_context = tsql_outmost_estat->stmt_mcontext_parent; + if (!tsql_outmost_context) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("pivot outer context not found"))); + + oldcontext = MemoryContextSwitchTo(tsql_outmost_context); + PG_TRY(); + { + per_pivot_list = list_nth_node(List, tsql_outmost_estat->pivot_parsetree_list, tsql_outmost_estat->pivot_number - 1); + Assert(list_length(per_pivot_list) >= 2); + bbf_pivot_src_sql = list_nth_node(RawStmt, per_pivot_list, 0); + bbf_pivot_cat_sql = list_nth_node(RawStmt, per_pivot_list, 1); + } + PG_FINALLY(); + { + MemoryContextSwitchTo(oldcontext); + } + PG_END_TRY(); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + /* get the requested return tuple description */ + tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); + + /* + * Check to make sure we have a reasonable tuple descriptor + * + * Note we will attempt to coerce the values into whatever the return + * attribute type is and depend on the "in" function to complain if + * needed. + */ + if (tupdesc->natts < 2) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("query-specified return tuple and " \ + "bbf_pivot function are not compatible"))); + + /* load up the categories hash table */ + bbf_pivot_hash = load_categories_hash(bbf_pivot_cat_sql, per_query_ctx); + + /* let the caller know we're sending back a tuplestore */ + rsinfo->returnMode = SFRM_Materialize; + + /* now go build it */ + rsinfo->setResult = get_bbf_pivot_tuplestore(bbf_pivot_src_sql, + bbf_pivot_hash, + tupdesc, + rsinfo->allowedModes & SFRM_Materialize_Random); + + /* + * SFRM_Materialize mode expects us to return a NULL Datum. The actual + * tuples are in our tuplestore and passed back through rsinfo->setResult. + * rsinfo->setDesc is set to the tuple description that we actually used + * to build our tuples with, so the caller can verify we did what it was + * expecting. + */ + rsinfo->setDesc = tupdesc; + MemoryContextSwitchTo(oldcontext); + + oldcontext = MemoryContextSwitchTo(tsql_outmost_context); + tsql_outmost_estat->pivot_parsetree_list = list_delete_nth_cell(tsql_outmost_estat->pivot_parsetree_list, tsql_outmost_estat->pivot_number - 1); + tsql_outmost_estat->pivot_number--; + MemoryContextSwitchTo(oldcontext); + return (Datum) 0; +} + +/* + * load up the categories hash table + */ +static HTAB * +load_categories_hash(RawStmt *cats_sql, MemoryContext per_query_ctx) +{ + HTAB *bbf_pivot_hash; + HASHCTL ctl; + int ret; + uint64 proc; + MemoryContext SPIcontext; + + /* initialize the category hash table */ + ctl.keysize = MAX_CATNAME_LEN; + ctl.entrysize = sizeof(bbf_pivot_HashEnt); + ctl.hcxt = per_query_ctx; + + /* + * use INIT_CATS, defined above as a guess of how many hash table entries + * to create, initially + */ + bbf_pivot_hash = hash_create("bbf_pivot hash", + INIT_CATS, + &ctl, + HASH_ELEM | HASH_STRINGS | HASH_CONTEXT); + + /* Connect to SPI manager */ + if ((ret = SPI_connect()) < 0) + /* internal error */ + elog(ERROR, "load_categories_hash: SPI_connect returned %d", ret); + + /* Retrieve the category name rows */ + ret = SPI_execute_raw_parsetree(cats_sql, true, 0); + proc = SPI_processed; + + /* Check for qualifying tuples */ + if ((ret == SPI_OK_SELECT) && (proc > 0)) + { + SPITupleTable *spi_tuptable = SPI_tuptable; + TupleDesc spi_tupdesc = spi_tuptable->tupdesc; + uint64 i; + + /* + * The provided categories SQL query must always return one column: + * category - the label or identifier for each column + */ + if (spi_tupdesc->natts != 1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("provided \"categories\" SQL must " \ + "return 1 column of at least one row"))); + + for (i = 0; i < proc; i++) + { + bbf_pivot_cat_desc *catdesc; + char *catname; + HeapTuple spi_tuple; + + /* get the next sql result tuple */ + spi_tuple = spi_tuptable->vals[i]; + + /* get the category from the current sql result tuple */ + catname = SPI_getvalue(spi_tuple, spi_tupdesc, 1); + if (catname == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("provided \"categories\" SQL must " \ + "not return NULL values"))); + + SPIcontext = MemoryContextSwitchTo(per_query_ctx); + catdesc = (bbf_pivot_cat_desc *) palloc(sizeof(bbf_pivot_cat_desc)); + catdesc->catname = catname; + catdesc->attidx = i; + /* Add the proc description block to the hashtable */ + bbf_pivot_HashTableInsert(bbf_pivot_hash, catdesc); + + MemoryContextSwitchTo(SPIcontext); + } + } + + if (SPI_finish() != SPI_OK_FINISH) + /* internal error */ + elog(ERROR, "load_categories_hash: SPI_finish() failed"); + + return bbf_pivot_hash; +} + + + +/* + * create and populate the bbf_pivot tuplestore + */ +static Tuplestorestate * +get_bbf_pivot_tuplestore(RawStmt *sql, + HTAB *bbf_pivot_hash, + TupleDesc tupdesc, + bool randomAccess) +{ + Tuplestorestate *tupstore; + int num_categories = hash_get_num_entries(bbf_pivot_hash); + AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc); + char **values; + HeapTuple tuple; + int ret; + uint64 proc; + + /* initialize our tuplestore (while still in query context!) */ + tupstore = tuplestore_begin_heap(randomAccess, false, work_mem); + + /* Connect to SPI manager */ + if ((ret = SPI_connect()) < 0) + /* internal error */ + elog(ERROR, "get_bbf_pivot_tuplestore: SPI_connect returned %d", ret); + + /* Now retrieve the bbf_pivot source rows */ + ret = SPI_execute_raw_parsetree(sql, true, 0); + proc = SPI_processed; + + /* Check for qualifying tuples */ + if ((ret == SPI_OK_SELECT) && (proc > 0)) + { + SPITupleTable *spi_tuptable = SPI_tuptable; + TupleDesc spi_tupdesc = spi_tuptable->tupdesc; + int ncols = spi_tupdesc->natts; + char **columngroup; + char **lastcolumngroup = NULL; + bool firstpass = true; + uint64 i; + int j; + int non_pivot_columns; + int result_ncols; + + if (num_categories == 0) + { + /* no qualifying category tuples */ + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("provided \"categories\" SQL must " \ + "return 1 column of at least one row"))); + } + + if (ncols < 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid source data SQL statement"), + errdetail("The provided SQL must return 2 " \ + " columns; category, and values."))); + + /* + * The last 2 columns of the results are category column and value column + * that will be used for later pivot operation. The remaining columns are + * non_pivot columns; + */ + non_pivot_columns = ncols - 2; + result_ncols = non_pivot_columns + num_categories; + + /* Recheck to make sure we tuple descriptor still looks reasonable */ + if (tupdesc->natts != result_ncols) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid return type"), + errdetail("Query-specified return " \ + "tuple has %d columns but bbf_pivot " \ + "returns %d.", tupdesc->natts, result_ncols))); + + /* allocate space and make sure it's clear */ + values = (char **) palloc0(result_ncols * sizeof(char *)); + columngroup = (char **) palloc0(non_pivot_columns * sizeof(char *)); + lastcolumngroup = (char **) palloc0(non_pivot_columns * sizeof(char *)); + + for (i = 0; i < proc; i++) + { + HeapTuple spi_tuple; + bbf_pivot_cat_desc *catdesc; + char *catname; + bool is_new_row = false; + + /* get the next sql result tuple */ + spi_tuple = spi_tuptable->vals[i]; + + if (ncols > 2) + { + /* get the non-pivot column group from the current sql result tuple */ + for (j = 0; j < non_pivot_columns; j++) + { + columngroup[j] = SPI_getvalue(spi_tuple, spi_tupdesc, j+1); + } + + /* + * if we're on a new output row, grab the column values up to + * column N-2 now + */ + + if (!firstpass) + { + for (j = 0; j < non_pivot_columns; j++) + { + if (!xstreq(columngroup[j], lastcolumngroup[j])) + { + is_new_row = true; + break; + } + } + } + + if (firstpass || is_new_row) + { + /* + * a new row means we need to flush the old one first, unless + * we're on the very first row + */ + if (!firstpass) + { + for (j = 0; j < result_ncols; j++) + { + if (values[j] == NULL) + values[j] = pstrdup("0"); + } + /* rowid changed, flush the previous output row */ + tuple = BuildTupleFromCStrings(attinmeta, values); + + tuplestore_puttuple(tupstore, tuple); + + for (j = 0; j < result_ncols; j++) + xpfree(values[j]); + } + + for (j = 0; j < non_pivot_columns; j++) + values[j] = SPI_getvalue(spi_tuple, spi_tupdesc, j + 1); + + /* we're no longer on the first pass */ + firstpass = false; + } + } + + /* look up the category and fill in the appropriate column */ + catname = SPI_getvalue(spi_tuple, spi_tupdesc, ncols - 1); + + if (catname != NULL) + { + bbf_pivot_HashTableLookup(bbf_pivot_hash, catname, catdesc); + + if (catdesc) + values[catdesc->attidx + non_pivot_columns] = + SPI_getvalue(spi_tuple, spi_tupdesc, ncols); + } + + if (ncols > 2) + { + for (j = 0; j < non_pivot_columns; j++) + { + xpfree(lastcolumngroup[j]); + xpstrdup(lastcolumngroup[j], columngroup[j]); + } + } + } + + /* flush the last output row */ + for (i = 0; i < result_ncols; i++) + { + if (values[i] == NULL) + values[i] = pstrdup("0"); + } + tuple = BuildTupleFromCStrings(attinmeta, values); + tuplestore_puttuple(tupstore, tuple); + } + + if (SPI_finish() != SPI_OK_FINISH) + /* internal error */ + elog(ERROR, "get_bbf_pivot_tuplestore: SPI_finish() failed"); + + return tupstore; +} diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in index dc99bb9af1..3c0d2f8842 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.in @@ -15,12 +15,15 @@ SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false) #include "sys_cast.sql" #include "coerce.sql" #include "object_definition_tsql.sql" +#include "linked_servers_tsql.sql" #include "ownership.sql" #include "sys_views.sql" #include "information_schema_tsql.sql" #include "sys_procedures.sql" #include "import_export_compatibility.sql" #include "babelfishpg_tsql.sql" +#include "fts_config.sql" +#include "fts_contains_pgconfig.sql" /* * Remove schema sys from search_path otherwise it causes BABEL-257 for some reason diff --git a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql index fd9a2799a9..f9f413e970 100644 --- a/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql @@ -376,8 +376,8 @@ CREATE OR REPLACE VIEW sys.sp_columns_100_view AS ) , sys.translate_pg_type_to_tsql(a.atttypid) AS tsql_type_name , sys.spt_datatype_info_table AS t5 - WHERE (t4."DATA_TYPE" = CAST(t5.TYPE_NAME AS sys.nvarchar(128))) - AND ext.dbid = cast(sys.db_id() as oid); + WHERE (t4."DATA_TYPE" = CAST(t5.TYPE_NAME AS sys.nvarchar(128)) OR (t4."DATA_TYPE" = 'bytea' AND t5.TYPE_NAME = 'image')) + AND ext.dbid = sys.db_id(); GRANT SELECT on sys.sp_columns_100_view TO PUBLIC; @@ -697,7 +697,7 @@ CREATE OR REPLACE PROCEDURE sys.sp_describe_first_result_set ( "@browse_information_mode" sys.tinyint = 0) AS $$ BEGIN - select * from sys.sp_describe_first_result_set_internal(@tsql, @params, @browse_information_mode); + select * from sys.sp_describe_first_result_set_internal(@tsql, @params, @browse_information_mode) order by column_ordinal; END; $$ LANGUAGE 'pltsql'; @@ -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.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, @@ -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, @@ -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; @@ -1128,7 +1128,7 @@ FROM pg_catalog.pg_class t1 WHERE t5.contype = 'p' AND CAST(t4."ORDINAL_POSITION" AS smallint) = ANY (t5.conkey) AND CAST(t4."ORDINAL_POSITION" AS smallint) = t5.conkey[seq] - AND ext.dbid = cast(sys.db_id() as oid); + AND ext.dbid = sys.db_id(); GRANT SELECT on sys.sp_pkeys_view TO PUBLIC; @@ -1199,7 +1199,7 @@ CAST(t1.relpages AS int) AS PAGES, CAST(NULL AS sys.varchar(128)) AS FILTER_CONDITION FROM pg_catalog.pg_class t1 JOIN sys.schemas s1 ON s1.schema_id = t1.relnamespace - JOIN information_schema_tsql.columns t3 ON (t1.relname = t3."TABLE_NAME" COLLATE sys.database_default AND s1.name = t3."TABLE_SCHEMA") + JOIN information_schema_tsql.columns t3 ON (lower(t1.relname) = lower(t3."TABLE_NAME") COLLATE C AND s1.name = t3."TABLE_SCHEMA") , generate_series(0,31) seq -- SQL server has max 32 columns per index UNION SELECT @@ -1230,7 +1230,7 @@ CAST(NULL AS sys.varchar(128)) AS FILTER_CONDITION FROM pg_catalog.pg_class t1 JOIN sys.schemas s1 ON s1.schema_id = t1.relnamespace JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid - JOIN information_schema_tsql.columns t4 ON (t1.relname = t4."TABLE_NAME" COLLATE sys.database_default AND s1.name = t4."TABLE_SCHEMA") + JOIN information_schema_tsql.columns t4 ON (lower(t1.relname) = lower(t4."TABLE_NAME") COLLATE C AND s1.name = t4."TABLE_SCHEMA") JOIN (pg_catalog.pg_index t5 JOIN pg_catalog.pg_class t6 ON t5.indexrelid = t6.oid) ON t1.oid = t5.indrelid JOIN pg_catalog.pg_namespace nsp ON (t1.relnamespace = nsp.oid) @@ -2546,6 +2546,61 @@ CREATE OR REPLACE FUNCTION sys.session_context ("@key" sys.sysname) RETURNS sys.SQL_VARIANT AS 'babelfishpg_tsql', 'session_context' LANGUAGE C; GRANT EXECUTE ON FUNCTION sys.session_context 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 is_srvrolemember('sysadmin', Base.name) = 1 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 +WHERE Base.type in ('S', 'U'); + +GRANT SELECT ON sys.syslogins TO PUBLIC; CREATE OR REPLACE VIEW sys.sp_sproc_columns_view AS @@ -2941,13 +2996,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 +3100,98 @@ 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' - 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 = '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; + 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 + -- 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 = sys.db_id() 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 + 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; @@ -3059,3 +3213,444 @@ 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; + +-- sp_babelfish_autoformat is a helper procedure which formats the contents of a table (or view) +-- as narrowly as possible given its actual column contents. +-- This proc is currently only used by sp_who but could be applied more generically. +-- A complication is that the metadata for #tmp tables cannot be found in the babelfish +-- catalogs, so we have to use some trickery to make things work. +-- Not all datatypes are handled as well as might be possible, but it is sufficient for +-- the current purposes. +-- Note that this proc may increase the response time for the first execution of sp_who, but +-- we are looking at prioritizing user-friendliness (easy-to-read output) here. Also, sp_who +-- is very unlikely to be part of performance-critical workload. +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_autoformat( + IN "@tab" sys.VARCHAR(257) DEFAULT NULL, + IN "@orderby" sys.VARCHAR(1000) DEFAULT '', + IN "@printrc" sys.bit DEFAULT 1, + IN "@hiddencols" sys.VARCHAR(1000) DEFAULT NULL) +LANGUAGE 'pltsql' +AS $$ +BEGIN + SET NOCOUNT ON + DECLARE @rc INT + DECLARE @id INT + DECLARE @objtype sys.VARCHAR(2) + DECLARE @msg sys.VARCHAR(200) + + IF @tab IS NULL + BEGIN + RAISERROR('Must specify table name', 16, 1) + RETURN + END + + IF TRIM(@tab) = '' + BEGIN + RAISERROR('Must specify table name', 16, 1) + RETURN + END + + -- Since we cannot find #tmp tables in the Babelfish catalogs, we cannot check + -- their existence other than by trying to select from them + -- Function sys.babelfish_get_enr_list() could be used to determine if a #tmp table + -- exists but the columns and datatypes can still not be retrieved, it would be of + -- little use here. + -- NB: not handling uncommon but valid T-SQL syntax '.#tmp' for #tmp tables + IF sys.SUBSTRING(@tab,1,1) <> '#' + BEGIN + SET @id = sys.OBJECT_ID(@tab) + IF @id IS NULL + BEGIN + IF sys.SUBSTRING(UPPER(@tab),1,4) = 'DBO.' + BEGIN + SET @id = sys.OBJECT_ID('SYS.' + sys.SUBSTRING(@tab,5)) + END + IF @id IS NULL + BEGIN + SET @msg = 'Table or view '''+@tab+''' not found' + RAISERROR(@msg, 16, 1) + RETURN + END + END + END + + SELECT @objtype = type COLLATE DATABASE_DEFAULT FROM sys.sysobjects WHERE id = @id + IF @objtype NOT IN ('U', 'S', 'V') + BEGIN + SET @msg = ''''+@tab+''' is not a table or view' + RAISERROR(@msg, 16, 1) + RETURN + END + + -- check for 'ORDER BY', if specified + SET @orderby = TRIM(@orderby) + IF @orderby <> '' + BEGIN + IF UPPER(@orderby) NOT LIKE 'ORDER BY%' + BEGIN + RAISERROR('@orderby parameter must start with ''ORDER BY''', 16, 1) + RETURN + END + END + + -- columns to hide in final client output + -- assuming delimited column names do not contain spaces or commas inside the name + -- remove any spaces around the commas: + WHILE (sys.CHARINDEX(' ,', @hiddencols) > 0) or (sys.CHARINDEX(', ', @hiddencols) > 0) + BEGIN + SET @hiddencols = sys.REPLACE(@hiddencols, ' ,', ',') + SET @hiddencols = sys.REPLACE(@hiddencols, ', ', ',') + END + IF sys.LEN(@hiddencols) IS NOT NULL SET @hiddencols = ',' + @hiddencols + ',' + SET @hiddencols = UPPER(@hiddencols) + + -- Need to use a guaranteed-uniquely named table as intermediate step since we cannot + -- access the metadata in case a #tmp table is passed as argument + -- But when we copy the #tmp table into another table, we get all the attributes and metadata + DECLARE @tmptab sys.VARCHAR(63) = 'sp_babelfish_autoformat' + sys.REPLACE(NEWID(), '-', '') + DECLARE @tmptab2 sys.VARCHAR(63) = 'sp_babelfish_autoformat' + sys.REPLACE(NEWID(), '-', '') + DECLARE @cmd sys.VARCHAR(1000) = 'SELECT * INTO ' + @tmptab + ' FROM ' + @tab + + BEGIN TRY + -- create the first work table + EXECUTE(@cmd) + + -- Get the columns + SELECT + c.name AS colname, c.colid AS colid, t.name AS basetype, 0 AS maxlen + INTO #sp_bbf_autoformat + FROM sys.syscolumns c left join sys.systypes t + ON c.xusertype = t.xusertype + WHERE c.id = sys.OBJECT_ID(@tmptab) + ORDER BY c.colid + + -- Get max length for each column based on the data + DECLARE @colname sys.VARCHAR(63), @basetype sys.VARCHAR(63), @maxlen int + DECLARE c CURSOR FOR SELECT colname, basetype, maxlen FROM #sp_bbf_autoformat ORDER BY colid + OPEN c + WHILE 1=1 + BEGIN + FETCH c INTO @colname, @basetype, @maxlen + IF @@fetch_status <> 0 BREAK + SET @cmd = 'DECLARE @i INT SELECT @i=ISNULL(MAX(sys.LEN(CAST([' + @colname + '] AS sys.VARCHAR(500)))),4) FROM ' + @tmptab + ' UPDATE #sp_bbf_autoformat SET maxlen = @i WHERE colname = ''' + @colname + '''' + EXECUTE(@cmd) + END + CLOSE c + DEALLOCATE c + + -- Generate the final SELECT + DECLARE @selectlist sys.VARCHAR(8000) = '' + DECLARE @collist sys.VARCHAR(8000) = '' + DECLARE @fmtstart sys.VARCHAR(30) = '' + DECLARE @fmtend sys.VARCHAR(30) = '' + OPEN c + WHILE 1=1 + BEGIN + FETCH c INTO @colname, @basetype, @maxlen + IF @@fetch_status <> 0 BREAK + IF sys.LEN(@colname) > @maxlen SET @maxlen = sys.LEN(@colname) + IF @maxlen <= 0 SET @maxlen = 1 + + IF (sys.CHARINDEX(',' + UPPER(@colname) + ',', @hiddencols) > 0) OR (sys.CHARINDEX(',[' + UPPER(@colname) + '],', @hiddencols) > 0) + BEGIN + SET @selectlist += ' [' + @colname + '],' + END + ELSE + BEGIN + SET @fmtstart = '' + SET @fmtend = '' + IF @basetype IN ('tinyint', 'smallint', 'int', 'bigint', 'decimal', 'numeric', 'real', 'float') + BEGIN + SET @fmtstart = 'CAST(right(space('+CAST(@maxlen AS sys.VARCHAR)+')+' + SET @fmtend = ','+CAST(@maxlen AS sys.VARCHAR)+') AS sys.VARCHAR(' + CAST(@maxlen AS sys.VARCHAR) + '))' + END + + SET @selectlist += ' '+@fmtstart+'CAST([' + @colname + '] AS sys.VARCHAR(' + CAST(@maxlen AS sys.VARCHAR) + '))'+@fmtend+' AS [' + @colname + '],' + SET @collist += '['+@colname + '],' + END + END + CLOSE c + DEALLOCATE c + + -- Remove redundant commas + SET @collist = sys.SUBSTRING(@collist, 1, sys.LEN(@collist)-1) + SET @selectlist = sys.SUBSTRING(@selectlist, 1, sys.LEN(@selectlist)-1) + SET @selectlist = 'SELECT ' + @selectlist + ' INTO ' + @tmptab2 + ' FROM ' + @tmptab + ' ' + @orderby + + -- create the second work table + EXECUTE(@selectlist) + + -- perform the final SELECT to generate the result set for the client + EXECUTE('SELECT ' + @collist + ' FROM ' + @tmptab2) + + -- PRINT rowcount if desired + SET @rc = @@rowcount + IF @printrc = 1 + BEGIN + PRINT ' ' + SET @cmd = '(' + CAST(@rc AS sys.VARCHAR) + ' rows affected)' + PRINT @cmd + END + + -- Cleanup: these work tables are permanent tables after all + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab) + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab2) + END TRY + BEGIN CATCH + -- Cleanup in case of an unexpected error + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab) + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab2) + END CATCH + + RETURN +END +$$; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_autoformat(IN sys.VARCHAR(257), IN sys.VARCHAR(1000), sys.bit, sys.VARCHAR(1000)) TO PUBLIC; + + +-- sp_who presents the contents of sysprocesses in a human-readable format. +-- With 'postgres' as argument or with optional second argument as 'postgres', +-- active PG connections will also be reported; by default only TDS connections are reported. +CREATE OR REPLACE PROCEDURE sys.sp_who( + IN "@loginame" sys.sysname DEFAULT NULL, + IN "@option" sys.VARCHAR(30) DEFAULT NULL) +LANGUAGE 'pltsql' +AS $$ +BEGIN + SET NOCOUNT ON + DECLARE @msg sys.VARCHAR(200) + DECLARE @show_pg BIT = 0 + DECLARE @hide_col sys.VARCHAR(50) + + IF @option IS NOT NULL + BEGIN + IF LOWER(TRIM(@option)) <> 'postgres' + BEGIN + RAISERROR('Parameter @option can only be ''postgres''', 16, 1) + RETURN + END + END + + -- Take a copy of sysprocesses so that we reference it only once + SELECT DISTINCT * INTO #sp_who_sysprocesses FROM sys.sysprocesses + + -- Get the executing statement for each spid and extract the main stmt type + -- This is for informational purposes only + SELECT pid, query INTO #sp_who_tmp FROM pg_stat_activity pgsa + + UPDATE #sp_who_tmp SET query = ' ' + TRIM(UPPER(query)) + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, chr(9), ' ') + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, chr(10), ' ') + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, chr(13), ' ') + WHILE (SELECT count(*) FROM #sp_who_tmp WHERE sys.CHARINDEX(' ',query)>0) > 0 + BEGIN + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, ' ', ' ') + END + + -- Determine type of stmt to report by sp_who: very basic only + -- NB: not handling presence of comments in the query string + UPDATE #sp_who_tmp + SET query = + CASE + WHEN PATINDEX('%[^a-zA-Z0-9_]UPDATE[^a-zA-Z0-9_]%', query) > 0 THEN 'UPDATE' + WHEN PATINDEX('%[^a-zA-Z0-9_]DELETE[^a-zA-Z0-9_]%', query) > 0 THEN 'DELETE' + WHEN PATINDEX('%[^a-zA-Z0-9_]INSERT[^a-zA-Z0-9_]%', query) > 0 THEN 'INSERT' + WHEN PATINDEX('%[^a-zA-Z0-9_]SELECT[^a-zA-Z0-9_]%', query) > 0 THEN 'SELECT' + WHEN PATINDEX('%[^a-zA-Z0-9_]WAITFOR[^a-zA-Z0-9_]%', query) > 0 THEN 'WAITFOR' + WHEN PATINDEX('%[^a-zA-Z0-9_]CREATE ]%', query) > 0 THEN sys.SUBSTRING(query,1,sys.CHARINDEX('CREATE ', query)) + WHEN PATINDEX('%[^a-zA-Z0-9_]ALTER ]%', query) > 0 THEN sys.SUBSTRING(query,1,sys.CHARINDEX('ALTER ', query)) + WHEN PATINDEX('%[^a-zA-Z0-9_]DROP ]%', query) > 0 THEN sys.SUBSTRING(query,1,sys.CHARINDEX('DROP ', query)) + ELSE sys.SUBSTRING(query, 1, sys.CHARINDEX(' ', query)) + END + + UPDATE #sp_who_tmp + SET query = sys.SUBSTRING(query,1, 8-1 + sys.CHARINDEX(' ', sys.SUBSTRING(query,8,99))) + WHERE query LIKE 'CREATE %' OR query LIKE 'ALTER %' OR query LIKE 'DROP %' + + -- The executing spid is always shown as doing a SELECT + UPDATE #sp_who_tmp SET query = 'SELECT' WHERE pid = @@spid + UPDATE #sp_who_tmp SET query = TRIM(query) + + -- Get all current connections + SELECT + spid, + MAX(blocked) AS blocked, + 0 AS ecid, + CAST('' AS sys.VARCHAR(100)) AS status, + CAST('' AS sys.VARCHAR(100)) AS loginname, + CAST('' AS sys.VARCHAR(100)) AS hostname, + 0 AS dbid, + CAST('' AS sys.VARCHAR(100)) AS cmd, + 0 AS request_id, + CAST('TDS' AS sys.VARCHAR(20)) AS connection, + hostprocess + INTO #sp_who_proc + FROM #sp_who_sysprocesses + GROUP BY spid, status, hostprocess + + -- Add attributes to each connection + UPDATE #sp_who_proc + SET ecid = sp.ecid, + status = sp.status, + loginname = sp.loginname, + hostname = sp.hostname, + dbid = sp.dbid, + request_id = sp.request_id + FROM #sp_who_sysprocesses sp + WHERE #sp_who_proc.spid = sp.spid + + -- Identify PG connections: the hostprocess PID comes from the TDS login packet + -- and therefore PG connections do not have a value here + UPDATE #sp_who_proc + SET connection = 'PostgreSQL' + WHERE hostprocess IS NULL + + -- Keep or delete PG connections + IF (LOWER(@loginame) = 'postgres' OR LOWER(@option) = 'postgres') + begin + -- Show PG connections; these have dbid = 0 + -- This is a Babelfish-specific enhancement, since PG connections may also be active in the Babelfish DB + -- and it may be useful to see these displayed + SET @show_pg = 1 + + -- blank out the loginame parameter for the tests below + IF LOWER(@loginame) = 'postgres' SET @loginame = NULL + END + + -- By default, do not show the column indicating the connection type since SQL Server does not have this column + SET @hide_col = 'connection' + + IF (@show_pg = 1) + BEGIN + SET @hide_col = '' + END + ELSE + BEGIN + -- Delete PG connections + DELETE #sp_who_proc + WHERE dbid = 0 + END + + -- Apply filter if specified + IF (@loginame IS NOT NULL) + BEGIN + IF (TRIM(@loginame) = '') + BEGIN + -- Raise error + SET @msg = ''''+@loginame+''' is not a valid login or you do not have permission.' + RAISERROR(@msg, 16, 1) + RETURN + END + + IF (sys.ISNUMERIC(@loginame) = 1) + BEGIN + -- Remove all connections except the specified one + DELETE #sp_who_proc + WHERE spid <> CAST(@loginame AS INT) + END + ELSE + BEGIN + IF (LOWER(@loginame) = 'active') + BEGIN + -- Remove all 'idle' connections + DELETE #sp_who_proc + WHERE status = 'idle' + END + ELSE + BEGIN + -- Verify the specified login name exists + IF (sys.SUSER_ID(@loginame) IS NULL) + BEGIN + SET @msg = ''''+@loginame+''' is not a valid login or you do not have permission.' + RAISERROR(@msg, 16, 1) + RETURN + END + ELSE + BEGIN + -- Keep only connections for the specified login + DELETE #sp_who_proc + WHERE sys.SUSER_ID(loginname) <> sys.SUSER_ID(@loginame) + END + END + END + END + + -- Create final result set; use DISTINCT since there are usually duplicate rows from the PG catalogs + SELECT distinct + p.spid AS spid, + p.ecid AS ecid, + CAST(LEFT(p.status,20) AS sys.VARCHAR(20)) AS status, + CAST(LEFT(p.loginname,40) AS sys.VARCHAR(40)) AS loginame, + CAST(LEFT(p.hostname,60) AS sys.VARCHAR(60)) AS hostname, + p.blocked AS blk, + CAST(LEFT(db_name(p.dbid),40) AS sys.VARCHAR(40)) AS dbname, + CAST(LEFT(#sp_who_tmp.query,30)as sys.VARCHAR(30)) AS cmd, + p.request_id AS request_id, + connection + INTO #sp_who_tmp2 + FROM #sp_who_proc p, #sp_who_tmp + WHERE p.spid = #sp_who_tmp.pid + ORDER BY spid + + -- Patch up remaining cases + UPDATE #sp_who_tmp2 + SET cmd = 'AWAITING COMMAND' + WHERE TRIM(ISNULL(cmd,'')) = '' AND status = 'idle' + + UPDATE #sp_who_tmp2 + SET cmd = 'UNKNOWN' + WHERE TRIM(cmd) = '' + + -- Format the result set as narrow as possible for readability + SET @hide_col += ',hostprocess' + EXECUTE sys.sp_babelfish_autoformat @tab='#sp_who_tmp2', @orderby='ORDER BY spid', @hiddencols=@hide_col, @printrc=0 + RETURN +END +$$; +GRANT EXECUTE ON PROCEDURE sys.sp_who(IN sys.sysname, IN sys.VARCHAR(30)) TO PUBLIC; + +-- Change the owner of the current database. +-- This is a wrapper around ALTER AUTHORIZATION ON DATABASE:: +CREATE OR REPLACE PROCEDURE sys.sp_changedbowner( + IN "@loginame" sys.sysname, + IN "@map" sys.VARCHAR(5) DEFAULT NULL) -- this parameter is ignored in T-SQL +LANGUAGE 'pltsql' +AS $$ +BEGIN + DECLARE @cmd sys.NVARCHAR(300) + DECLARE @db sys.sysname = DB_NAME() + + -- For a NULL login name, do nothing + IF @loginame IS NULL + BEGIN + RETURN + END + + IF (@db = 'master') OR (@db = 'tempdb') + BEGIN + RAISERROR('Cannot change the owner of the master or tempdb database.', 16, 1) + RETURN + END + + IF SUSER_ID(@loginame) IS NULL + BEGIN + RAISERROR('Cannot find the principal ''%s'', because it does not exist or you do not have permission.', 16, 1, @loginame) + RETURN + END + + -- Compose the ALTER ATHORIZATION statement: + SET @cmd = 'ALTER AUTHORIZATION ON DATABASE::[' + @db + '] TO [' + SUSER_NAME(SUSER_ID(@loginame)) + ']' + EXECUTE(@cmd) +END +$$; +GRANT EXECUTE ON PROCEDURE sys.sp_changedbowner(IN sys.sysname, IN sys.VARCHAR(5)) TO PUBLIC; + diff --git a/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql b/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql index ac26898f8c..2a23de9f88 100644 --- a/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql +++ b/contrib/babelfishpg_tsql/sql/datatype_string_operators.sql @@ -57,15 +57,15 @@ CREATE OR REPLACE FUNCTION sys.formatmessage(IN message_str VARCHAR, VARIADIC "a AS 'babelfishpg_tsql', 'formatmessage' LANGUAGE C IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.formatmessage(IN VARCHAR, VARIADIC "any") TO PUBLIC; -CREATE OR REPLACE FUNCTION sys.format_datetime(IN value anyelement, IN format_pattern NVARCHAR,IN culture VARCHAR, IN data_type VARCHAR DEFAULT '') RETURNS sys.nvarchar -AS 'babelfishpg_tsql', 'format_datetime' LANGUAGE C IMMUTABLE PARALLEL SAFE; -GRANT EXECUTE ON FUNCTION sys.format_datetime(IN anyelement, IN NVARCHAR, IN VARCHAR, IN VARCHAR) TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.format_datetime(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '') RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'format_datetime' LANGUAGE C IMMUTABLE PARALLEL UNSAFE; +GRANT EXECUTE ON FUNCTION sys.format_datetime(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR) TO PUBLIC; -CREATE OR REPLACE FUNCTION sys.format_numeric(IN value anyelement, IN format_pattern NVARCHAR,IN culture VARCHAR, IN data_type VARCHAR DEFAULT '', IN e_position INT DEFAULT -1) RETURNS sys.nvarchar -AS 'babelfishpg_tsql', 'format_numeric' LANGUAGE C IMMUTABLE PARALLEL SAFE; -GRANT EXECUTE ON FUNCTION sys.format_numeric(IN anyelement, IN NVARCHAR, IN VARCHAR, IN VARCHAR, IN INT) TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.format_numeric(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '', IN e_position INT DEFAULT -1) RETURNS sys.nvarchar +AS 'babelfishpg_tsql', 'format_numeric' LANGUAGE C IMMUTABLE PARALLEL UNSAFE; +GRANT EXECUTE ON FUNCTION sys.format_numeric(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR, IN INT) TO PUBLIC; -CREATE OR REPLACE FUNCTION sys.FORMAT(IN arg anyelement, IN p_format_pattern NVARCHAR, IN p_culture VARCHAR default 'en-us') +CREATE OR REPLACE FUNCTION sys.FORMAT(IN arg anyelement, IN p_format_pattern sys.NVARCHAR, IN p_culture sys.VARCHAR default 'en-us') RETURNS sys.NVARCHAR AS $BODY$ @@ -123,8 +123,8 @@ EXCEPTION HINT := 'Convert it to valid datatype and try again.'; END; $BODY$ -LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; -GRANT EXECUTE ON FUNCTION sys.FORMAT(IN anyelement, IN NVARCHAR, IN VARCHAR) TO PUBLIC; +LANGUAGE plpgsql IMMUTABLE PARALLEL UNSAFE; +GRANT EXECUTE ON FUNCTION sys.FORMAT(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR) TO PUBLIC; CREATE OR REPLACE FUNCTION sys.STR(IN float_expression NUMERIC, IN length INTEGER DEFAULT 10, IN decimal_point INTEGER DEFAULT 0) RETURNS VARCHAR AS diff --git a/contrib/babelfishpg_tsql/sql/fts_config.sql b/contrib/babelfishpg_tsql/sql/fts_config.sql new file mode 100644 index 0000000000..9aa1b67722 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/fts_config.sql @@ -0,0 +1,58 @@ +-- tsql full-text search configurations for Babelfish +-- Since currently we only support one language - American English, +-- the configurations are for American English only + +-- create a configuration fts_contains_simple for simple terms search +CREATE TEXT SEARCH DICTIONARY fts_contains_simple_dict ( + TEMPLATE = simple, + STOPWORDS = tsql_contains +); + +COMMENT ON TEXT SEARCH DICTIONARY fts_contains_simple_dict IS 'Babelfish T-SQL full text search CONTAINS dictionary (currently we only support American English)'; + +CREATE TEXT SEARCH CONFIGURATION fts_contains_simple ( COPY = simple ); + +COMMENT ON TEXT SEARCH CONFIGURATION fts_contains_simple IS 'Babelfish T-SQL full text search CONTAINS configuration (currently we only support American English)'; + +ALTER TEXT SEARCH CONFIGURATION fts_contains_simple + ALTER MAPPING FOR asciiword, asciihword, hword_asciipart, + word, hword, hword_part + WITH fts_contains_simple_dict; + + + +-- Create a configuration english_inflectional_babel for inflectional search +-- first english_inflectional_babel is created as a copy of the build-in Postgres english configuration +CREATE TEXT SEARCH DICTIONARY english_stem_babel + (TEMPLATE = snowball, Language = english , StopWords=tsql_contains); + +COMMENT ON TEXT SEARCH DICTIONARY english_stem_babel IS 'snowball stemmer for english_inflectional_babel language'; + +CREATE TEXT SEARCH CONFIGURATION english_inflectional_babel + (PARSER = default); + +COMMENT ON TEXT SEARCH CONFIGURATION english_inflectional_babel IS 'configuration for english_inflectional_babel language'; + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel ADD MAPPING + FOR email, url, url_path, host, file, version, + sfloat, float, int, uint, + numword, hword_numpart, numhword + WITH simple; + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel ADD MAPPING + FOR asciiword, hword_asciipart, asciihword + WITH english_stem_babel; + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel ADD MAPPING + FOR word, hword_part, hword + WITH english_stem_babel; + +-- then we add irregular verbs as synonym files to english_inflectional_babel for inflectional search +CREATE TEXT SEARCH DICTIONARY irregular_verbs ( + TEMPLATE = synonym, + SYNONYMS = irregular_verbs +); + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel + ALTER MAPPING FOR asciiword + WITH irregular_verbs, english_stem_babel; diff --git a/contrib/babelfishpg_tsql/sql/fts_contains_pgconfig.sql b/contrib/babelfishpg_tsql/sql/fts_contains_pgconfig.sql new file mode 100644 index 0000000000..ce40c1ea4e --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/fts_contains_pgconfig.sql @@ -0,0 +1,37 @@ +-- Given the query string, determine the Postgres full text configuration to use +-- Currently we only support simple terms and prefix terms +-- For simple terms, we use the 'fts_contains_simple' configuration +-- For prefix terms, we use the 'simple' configuration +-- They are the configurations that provide closest matching according to our experiments +CREATE OR REPLACE FUNCTION sys.babelfish_fts_contains_pgconfig(IN phrase text) + RETURNS regconfig AS +$$ +DECLARE + joined_text text; + word text; +BEGIN + /* 'Prefix term (Examples: '"word1*"', '"word1 word2*"') if + * (1) search term is surrounded by double quotes (Counter example: 'word1*', as it doesn't have double quotes) + * (2) last word in the search term ends with a star (Counter example: '"word1* word2"', as last word doesn't end with star) + * (3) last word is NOT a single star (Counter example: '"*"', '"word1 word2 *"', as last word is a single star) + */ + IF (phrase COLLATE C) SIMILAR TO ('[ ]*"%\*"[ ]*' COLLATE C) AND (NOT (phrase COLLATE C) SIMILAR TO ('[ ]*"% \*"[ ]*' COLLATE C)) AND (NOT (phrase COLLATE C) SIMILAR TO ('[ ]*"\*"[ ]*' COLLATE C)) THEN + RETURN 'simple'::regconfig; + END IF; + + -- Generation term, inflectional (Examples: 'FORMSOF(INFLECTIONAL, love)', 'FORMSOF(INFLECTIONAL, "move forward")', 'FORMSOF(INFLECTIONAL, play, "plan to")') + IF UPPER(phrase COLLATE C) SIMILAR TO ('[ ]*FORMSOF\(INFLECTIONAL,%\)[ ]*' COLLATE C) THEN + RETURN 'english_inflectional_babel'::regconfig; + END IF; + + -- Generation term, thesaurus (Examples: 'FORMSOF(THESAURUS, love)', 'FORMSOF(THESAURUS, "move forward")', 'FORMSOF(THESAURUS, play, "plan to")') + -- By default, SQL Server thesaurus search does not use any thesaurus files so behavior is identical to simple terms + IF UPPER(phrase COLLATE C) SIMILAR TO ('[ ]*FORMSOF\(THESAURUS,%\)[ ]*' COLLATE C) THEN + RETURN 'fts_contains_simple'::regconfig; + END IF; + + -- Simple term + RETURN 'fts_contains_simple'::regconfig; +END; +$$ +LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/sql/information_schema_tsql.sql b/contrib/babelfishpg_tsql/sql/information_schema_tsql.sql index c2908110e5..16d4546b24 100644 --- a/contrib/babelfishpg_tsql/sql/information_schema_tsql.sql +++ b/contrib/babelfishpg_tsql/sql/information_schema_tsql.sql @@ -250,6 +250,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.columns AS CAST( CASE WHEN tsql_type_name = 'sysname' THEN sys.translate_pg_type_to_tsql(t.typbasetype) + WHEN tsql_type_name.tsql_type_name IS NULL THEN format_type(t.oid, NULL::integer) ELSE tsql_type_name END AS sys.nvarchar(128)) AS "DATA_TYPE", @@ -326,7 +327,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.columns AS AND (pg_has_role(c.relowner, 'USAGE') OR has_column_privilege(c.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES')) - AND ext.dbid = cast(sys.db_id() as oid); + AND ext.dbid =sys.db_id(); GRANT SELECT ON information_schema_tsql.columns TO PUBLIC; @@ -394,7 +395,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.domains AS WHERE (pg_has_role(t.typowner, 'USAGE') OR has_type_privilege(t.oid, 'USAGE')) AND (t.typtype = 'd' OR is_tbl_type) - AND ext.dbid = cast(sys.db_id() as oid); + AND ext.dbid = sys.db_id(); GRANT SELECT ON information_schema_tsql.domains TO PUBLIC; @@ -414,7 +415,7 @@ CREATE VIEW information_schema_tsql.tables AS CASE WHEN c.relkind IN ('r', 'p') THEN 'BASE TABLE' WHEN c.relkind = 'v' THEN 'VIEW' ELSE null END - AS varchar(10)) AS "TABLE_TYPE" + AS sys.varchar(10)) COLLATE sys.database_default AS "TABLE_TYPE" FROM sys.pg_namespace_ext nc JOIN pg_class c ON (nc.oid = c.relnamespace) LEFT OUTER JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname @@ -424,7 +425,7 @@ CREATE VIEW information_schema_tsql.tables AS AND (pg_has_role(c.relowner, 'USAGE') OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) - AND ext.dbid = cast(sys.db_id() as oid) + AND ext.dbid = sys.db_id() AND (NOT c.relname = 'sysdatabases'); GRANT SELECT ON information_schema_tsql.tables TO PUBLIC; @@ -462,7 +463,7 @@ CREATE VIEW information_schema_tsql.table_constraints AS AND (pg_has_role(r.relowner, 'USAGE') OR has_table_privilege(r.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') OR has_any_column_privilege(r.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) - AND extc.dbid = cast(sys.db_id() as oid); + AND extc.dbid = sys.db_id(); GRANT SELECT ON information_schema_tsql.table_constraints TO PUBLIC; @@ -497,7 +498,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.views AS AND (pg_has_role(c.relowner, 'USAGE') OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) - AND ext.dbid = cast(sys.db_id() as oid); + AND ext.dbid = sys.db_id(); GRANT SELECT ON information_schema_tsql.views TO PUBLIC; @@ -523,7 +524,7 @@ CREATE VIEW information_schema_tsql.check_constraints AS AND (pg_has_role(r.relowner, 'USAGE') OR has_table_privilege(r.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') OR has_any_column_privilege(r.oid, 'SELECT, INSERT, UPDATE, REFERENCES')) - AND extc.dbid = cast(sys.db_id() as oid); + AND extc.dbid = sys.db_id(); GRANT SELECT ON information_schema_tsql.check_constraints TO PUBLIC; @@ -711,7 +712,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.routines AS AND has_function_privilege(p.oid, 'EXECUTE') AND (pg_has_role(t.typowner, 'USAGE') OR has_type_privilege(t.oid, 'USAGE')) - AND ext.dbid = cast(sys.db_id() as oid) + AND ext.dbid = sys.db_id() AND p.prolang = l.oid AND p.prorettype = t.oid AND p.pronamespace = nc.oid @@ -743,7 +744,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.SEQUENCES AS pg_sequence s join pg_class r on s.seqrelid = r.oid join pg_type t on s.seqtypid=t.oid, sys.translate_pg_type_to_tsql(s.seqtypid) AS tsql_type_name WHERE nc.oid = r.relnamespace - AND extc.dbid = cast(sys.db_id() as oid) + AND extc.dbid = sys.db_id() AND r.relkind = 'S' AND (NOT pg_is_other_temp_schema(nc.oid)) AND (pg_has_role(r.relowner, 'USAGE') @@ -751,6 +752,30 @@ CREATE OR REPLACE VIEW information_schema_tsql.SEQUENCES AS GRANT SELECT ON information_schema_tsql.sequences TO PUBLIC; +CREATE OR REPLACE VIEW information_schema_tsql.key_column_usage AS + SELECT + CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA", + CAST(c.conname AS sys.nvarchar(128)) AS "CONSTRAINT_NAME", + CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(r.relname AS sys.nvarchar(128)) AS "TABLE_NAME", + CAST(a.attname AS sys.nvarchar(128)) AS "COLUMN_NAME", + CAST(ord AS int) AS "ORDINAL_POSITION" + FROM + pg_constraint c + JOIN pg_class r ON r.oid = c.conrelid AND c.contype in ('p','u','f') AND r.relkind in ('r','p') + JOIN sys.pg_namespace_ext nc ON nc.oid = c.connamespace AND r.relnamespace = nc.oid + JOIN sys.babelfish_namespace_ext ext ON ext.nspname = nc.nspname AND ext.dbid = sys.db_id() + CROSS JOIN unnest(c.conkey) WITH ORDINALITY AS ak(j,ord) + LEFT JOIN pg_attribute a ON a.attrelid = r.oid AND a.attnum = ak.j + WHERE + pg_has_role(r.relowner, 'USAGE'::text) + OR has_column_privilege(r.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + AND NOT pg_is_other_temp_schema(nc.oid) + ; +GRANT SELECT ON information_schema_tsql.key_column_usage TO PUBLIC; + /* * SCHEMATA view */ @@ -774,7 +799,7 @@ CREATE OR REPLACE VIEW information_schema_tsql.schemata AS CAST(null AS sys.sysname) AS "DEFAULT_CHARACTER_SET_NAME" FROM ((pg_catalog.pg_namespace np LEFT JOIN sys.pg_namespace_ext nc on np.nspname = nc.nspname) LEFT JOIN pg_catalog.pg_roles r on r.oid = nc.nspowner) LEFT JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname - WHERE (ext.dbid = cast(sys.db_id() as oid) OR np.nspname in ('sys', 'information_schema_tsql')) AND + WHERE (ext.dbid = sys.db_id() OR np.nspname in ('sys', 'information_schema_tsql')) AND (pg_has_role(np.nspowner, 'USAGE') OR has_schema_privilege(np.oid, 'CREATE, USAGE')) ORDER BY nc.nspname, np.nspname; diff --git a/contrib/babelfishpg_tsql/sql/linked_servers_tsql.sql b/contrib/babelfishpg_tsql/sql/linked_servers_tsql.sql new file mode 100644 index 0000000000..2e8c0f0174 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/linked_servers_tsql.sql @@ -0,0 +1,8 @@ +CREATE TABLE sys.babelfish_server_options ( + servername sys.SYSNAME NOT NULL PRIMARY KEY COLLATE "C", + query_timeout INT, + connect_timeout INT +); +GRANT SELECT ON sys.babelfish_server_options TO PUBLIC; + +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_server_options', ''); diff --git a/contrib/babelfishpg_tsql/sql/ownership.sql b/contrib/babelfishpg_tsql/sql/ownership.sql index 1760aacc63..ee3a5446a4 100644 --- a/contrib/babelfishpg_tsql/sql/ownership.sql +++ b/contrib/babelfishpg_tsql/sql/ownership.sql @@ -14,6 +14,17 @@ CREATE TABLE sys.babelfish_sysdatabases ( GRANT SELECT on sys.babelfish_sysdatabases TO PUBLIC; +-- BABELFISH_SCHEMA_PERMISSIONS +CREATE TABLE sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name NAME NOT NULL, + object_name NAME NOT NULL, + permission NAME NOT NULL, + grantee NAME NOT NULL, + object_type NAME, + PRIMARY KEY(dbid, schema_name, object_name, permission, grantee) +); + -- BABELFISH_FUNCTION_EXT CREATE TABLE sys.babelfish_function_ext ( nspname NAME NOT NULL, @@ -77,9 +88,9 @@ select CAST(ext.orig_name as sys.SYSNAME) as name , base.oid as schema_id , base.nspowner as principal_id -from pg_catalog.pg_namespace base INNER JOIN sys.babelfish_namespace_ext ext on base.nspname = ext.nspname -where base.nspname not in ('information_schema', 'pg_catalog', 'pg_toast', 'sys', 'public') -and ext.dbid = cast(sys.db_id() as oid); +from pg_catalog.pg_namespace base +inner join sys.babelfish_namespace_ext ext on base.nspname = ext.nspname +where ext.dbid = sys.db_id(); GRANT SELECT ON sys.schemas TO PUBLIC; CREATE SEQUENCE sys.babelfish_db_seq MAXVALUE 32767 CYCLE; @@ -199,11 +210,47 @@ BEGIN ALTER PROCEDURE master_dbo.sp_dropserver OWNER TO sysadmin; + CREATE OR REPLACE PROCEDURE master_dbo.sp_testlinkedserver( IN "@servername" sys.sysname) + AS 'babelfishpg_tsql', 'sp_testlinkedserver_internal' + LANGUAGE C; + + ALTER PROCEDURE master_dbo.sp_testlinkedserver OWNER TO sysadmin; + + CREATE OR REPLACE PROCEDURE master_dbo.sp_enum_oledb_providers() + AS 'babelfishpg_tsql', 'sp_enum_oledb_providers_internal' + LANGUAGE C; + + ALTER PROCEDURE master_dbo.sp_enum_oledb_providers OWNER TO sysadmin; + -- let sysadmin only to update babelfish_domain_mapping GRANT ALL ON TABLE sys.babelfish_domain_mapping TO sysadmin; END $$; +CREATE OR REPLACE PROCEDURE sys.analyze_babelfish_catalogs() +LANGUAGE plpgsql +AS $$ +DECLARE + babelfish_catalog RECORD; + schema_name varchar = 'sys'; + error_msg text; +BEGIN + FOR babelfish_catalog IN ( + SELECT relname as name from pg_class t + INNER JOIN pg_namespace n on n.oid = t.relnamespace + WHERE t.relkind = 'r' and n.nspname = schema_name + ) + LOOP + BEGIN + EXECUTE format('ANALYZE %I.%I', schema_name, babelfish_catalog.name); + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS error_msg = MESSAGE_TEXT; + RAISE WARNING 'ANALYZE for babelfish catalog %.% failed with error: %s', schema_name, babelfish_catalog.name, error_msg; + END; + END LOOP; +END; +$$; + CREATE OR REPLACE PROCEDURE initialize_babelfish ( sa_name VARCHAR(128) ) LANGUAGE plpgsql AS $$ @@ -243,6 +290,8 @@ BEGIN CALL sys.babel_initialize_logins('sysadmin'); CALL sys.babel_create_builtin_dbs(sa_name); CALL sys.initialize_babel_extras(); + -- run analyze for all babelfish catalog + CALL sys.analyze_babelfish_catalogs(); END $$; @@ -286,10 +335,10 @@ CAST(CAST(Base.oid as INT) as sys.varbinary(85)) AS sid, CAST(Ext.type AS CHAR(1)) as type, CAST( CASE - WHEN Ext.type = 'S' THEN 'SQL_LOGIN' + WHEN Ext.type = 'S' THEN 'SQL_LOGIN' WHEN Ext.type = 'R' THEN 'SERVER_ROLE' WHEN Ext.type = 'U' THEN 'WINDOWS_LOGIN' - ELSE NULL + ELSE NULL END AS NVARCHAR(60)) AS type_desc, CAST(Ext.is_disabled AS INT) AS is_disabled, @@ -300,10 +349,15 @@ CAST(Ext.default_language_name AS SYS.SYSNAME) AS default_language_name, CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.credential_id END AS INT) AS credential_id, CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.owning_principal_id END AS INT) AS owning_principal_id, CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.is_fixed_role END AS sys.BIT) AS is_fixed_role -FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname; +FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname +WHERE pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER') +OR Ext.orig_loginname = suser_name() +OR Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default +OR Ext.type = 'R'; GRANT SELECT ON sys.server_principals TO PUBLIC; + -- USER extension CREATE TABLE sys.babelfish_authid_user_ext ( rolname NAME NOT NULL, @@ -335,17 +389,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,10 +417,79 @@ 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; +-- 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 @@ -383,6 +507,20 @@ AND Ext2.orig_username != 'db_owner'; GRANT SELECT ON sys.database_role_members TO PUBLIC; +--SERVER_ROLE_MEMBER +CREATE OR REPLACE VIEW sys.server_role_members AS +SELECT +CAST(Authmbr.roleid AS INT) AS role_principal_id, +CAST(Authmbr.member AS INT) AS member_principal_id +FROM pg_catalog.pg_auth_members AS Authmbr +INNER JOIN pg_catalog.pg_roles AS Auth1 ON Auth1.oid = Authmbr.roleid +INNER JOIN pg_catalog.pg_roles AS Auth2 ON Auth2.oid = Authmbr.member +INNER JOIN sys.babelfish_authid_login_ext AS Ext1 ON Auth1.rolname = Ext1.rolname +INNER JOIN sys.babelfish_authid_login_ext AS Ext2 ON Auth2.rolname = Ext2.rolname +WHERE Ext1.type = 'R'; + +GRANT SELECT ON sys.server_role_members TO PUBLIC; + -- internal table function for sp_helpdb with no arguments CREATE OR REPLACE FUNCTION sys.babelfish_helpdb() RETURNS table ( @@ -540,4 +678,66 @@ GRANT EXECUTE ON PROCEDURE sys.babelfish_remove_domain_mapping_entry TO PUBLIC; CREATE OR REPLACE PROCEDURE sys.babelfish_truncate_domain_mapping_table() AS 'babelfishpg_tsql', 'babelfish_truncate_domain_mapping_table_internal' LANGUAGE C; -GRANT EXECUTE ON PROCEDURE sys.babelfish_truncate_domain_mapping_table TO PUBLIC; \ No newline at end of file +GRANT EXECUTE ON PROCEDURE sys.babelfish_truncate_domain_mapping_table TO PUBLIC; + +CREATE TABLE sys.babelfish_extended_properties ( + dbid smallint NOT NULL, + schema_name name NOT NULL, + major_name name NOT NULL, + minor_name name NOT NULL, + type sys.varchar(50) NOT NULL, + name sys.sysname NOT NULL, + orig_name sys.sysname NOT NULL, + value sys.sql_variant, + PRIMARY KEY (dbid, type, schema_name, major_name, minor_name, name) +); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_extended_properties', ''); + +-- This view contains many outer joins that could potentially impair performance. +-- To optimize this, it may be beneficial to begin by acquiring the object identifier (OID) and verifying permissions. +CREATE OR REPLACE VIEW sys.extended_properties +AS +SELECT + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 0 + WHEN ep.type = 'SCHEMA' THEN 3 + WHEN ep.type IN ('TABLE', 'TABLE COLUMN', 'VIEW', 'SEQUENCE', 'PROCEDURE', 'FUNCTION') THEN 1 + WHEN ep.type = 'TYPE' THEN 6 + END) AS sys.tinyint) AS class, + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 'DATABASE' + WHEN ep.type = 'SCHEMA' THEN 'SCHEMA' + WHEN ep.type IN ('TABLE', 'TABLE COLUMN', 'VIEW', 'SEQUENCE', 'PROCEDURE', 'FUNCTION') THEN 'OBJECT_OR_COLUMN' + WHEN ep.type = 'TYPE' THEN 'TYPE' + END) AS sys.nvarchar(60)) AS class_desc, + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 0 + WHEN ep.type = 'SCHEMA' THEN n.oid + WHEN ep.type IN ('TABLE', 'TABLE COLUMN', 'VIEW', 'SEQUENCE') THEN c.oid + WHEN ep.type IN ('PROCEDURE', 'FUNCTION') THEN p.oid + WHEN ep.type = 'TYPE' THEN t.oid + END) AS int) AS major_id, + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 0 + WHEN ep.type = 'SCHEMA' THEN 0 + WHEN ep.type IN ('TABLE', 'VIEW', 'SEQUENCE', 'PROCEDURE', 'FUNCTION', 'TYPE') THEN 0 + WHEN ep.type = 'TABLE COLUMN' THEN a.attnum + END) AS int) AS minor_id, + ep.orig_name AS name, ep.value AS value + FROM sys.babelfish_extended_properties ep + LEFT JOIN pg_catalog.pg_namespace n ON n.nspname = ep.schema_name + LEFT JOIN pg_catalog.pg_class c ON c.relname = ep.major_name AND c.relnamespace = n.oid + LEFT JOIN pg_catalog.pg_proc p ON p.proname = ep.major_name AND p.pronamespace = n.oid + LEFT JOIN pg_catalog.pg_type t ON t.typname = ep.major_name AND t.typnamespace = n.oid + LEFT JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid AND a.attname = ep.minor_name + WHERE ep.dbid = sys.db_id() AND + (CASE + WHEN ep.type = 'DATABASE' THEN true + WHEN ep.type = 'SCHEMA' THEN has_schema_privilege(n.oid, 'USAGE, CREATE') + WHEN ep.type IN ('TABLE', 'VIEW', 'SEQUENCE') THEN (has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')) + WHEN ep.type IN ('TABLE COLUMN') THEN (has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') OR has_column_privilege(a.attrelid, a.attname, 'SELECT, INSERT, UPDATE, REFERENCES')) + WHEN ep.type IN ('PROCEDURE', 'FUNCTION') THEN has_function_privilege(p.oid, 'EXECUTE') + WHEN ep.type = 'TYPE' THEN has_type_privilege(t.oid, 'USAGE') + END) + ORDER BY class, class_desc, major_id, minor_id, ep.orig_name; +GRANT SELECT ON sys.extended_properties TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/sys.sql b/contrib/babelfishpg_tsql/sql/sys.sql index 605a3b3951..9159652d2b 100644 --- a/contrib/babelfishpg_tsql/sql/sys.sql +++ b/contrib/babelfishpg_tsql/sql/sys.sql @@ -1,32 +1,27 @@ /* Built in functions */ -CREATE FUNCTION sys.sysdatetime() RETURNS datetime2 - AS $$select clock_timestamp()::datetime2;$$ - LANGUAGE SQL; -GRANT EXECUTE ON FUNCTION sys.sysdatetime() TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.sysdatetime() RETURNS datetime2 +AS 'babelfishpg_tsql', 'sysdatetime' +LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.sysdatetime() TO PUBLIC; -CREATE FUNCTION sys.sysdatetimeoffset() RETURNS sys.datetimeoffset - -- Casting to text as there are not type cast function from timestamptz to datetimeoffset - AS $$select cast(cast(clock_timestamp() as text) as sys.datetimeoffset);$$ - LANGUAGE SQL STABLE; -GRANT EXECUTE ON FUNCTION sys.sysdatetimeoffset() TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.sysdatetimeoffset() RETURNS sys.datetimeoffset +AS 'babelfishpg_tsql', 'sysdatetimeoffset' +LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.sysdatetimeoffset() TO PUBLIC; -CREATE FUNCTION sys.sysutcdatetime() RETURNS sys.datetime2 - AS $$select (clock_timestamp() AT TIME ZONE 'UTC'::pg_catalog.text)::sys.datetime2;$$ - LANGUAGE SQL STABLE; -GRANT EXECUTE ON FUNCTION sys.sysutcdatetime() TO PUBLIC; +CREATE OR REPLACE FUNCTION sys.sysutcdatetime() returns sys.datetime2 +AS 'babelfishpg_tsql', 'sysutcdatetime' +LANGUAGE C STABLE; +CREATE OR REPLACE FUNCTION sys.getdate() RETURNS sys.datetime +AS 'babelfishpg_tsql', 'getdate_internal' +LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.getdate() TO PUBLIC; -CREATE FUNCTION sys.getdate() RETURNS sys.datetime - AS $$select date_trunc('millisecond', clock_timestamp()::pg_catalog.timestamp)::sys.datetime;$$ - LANGUAGE SQL STABLE; -GRANT EXECUTE ON FUNCTION sys.getdate() TO PUBLIC; - - -CREATE FUNCTION sys.getutcdate() RETURNS sys.datetime - AS $$select date_trunc('millisecond', clock_timestamp() AT TIME ZONE 'UTC')::sys.datetime;$$ - LANGUAGE SQL; -GRANT EXECUTE ON FUNCTION sys.getutcdate() TO PUBLIC; +create or replace function sys.getutcdate() returns sys.datetime +AS 'babelfishpg_tsql', 'getutcdate' +LANGUAGE C STABLE; CREATE FUNCTION sys.isnull(text,text) RETURNS text AS $$ diff --git a/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql b/contrib/babelfishpg_tsql/sql/sys_function_helpers.sql index 51d92c2059..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; @@ -10352,3 +10357,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 0417e41e12..e4a7070b54 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) @@ -274,7 +279,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 +287,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 +302,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 +311,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.', @@ -342,6 +353,157 @@ LANGUAGE plpgsql IMMUTABLE RETURNS NULL ON NULL INPUT; +CREATE OR REPLACE FUNCTION sys.TODATETIMEOFFSET(IN input_expr PG_CATALOG.TEXT , IN tz_offset TEXT) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + v_string pg_catalog.text; + v_sign pg_catalog.text; + str_hr TEXT; + str_mi TEXT; + precision_str TEXT; + sign_flag INTEGER; + v_hr INTEGER; + v_mi INTEGER; + v_precision INTEGER; + input_expr_datetime2 datetime2; +BEGIN + + BEGIN + input_expr_datetime2 := cast(input_expr as sys.datetime2); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + IF input_expr IS NULL or tz_offset IS NULL THEN + RETURN NULL; + END IF; + + IF tz_offset LIKE '+__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := 1; + ELSIF tz_offset LIKE '-__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := -1; + ELSE + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + BEGIN + v_hr := str_hr::INTEGER; + v_mi := str_mi ::INTEGER; + exception + WHEN others THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END; + + + if v_hr > 14 or (v_hr = 14 and v_mi > 0) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + v_hr := v_hr * sign_flag; + + v_string := CONCAT(input_expr_datetime2::pg_catalog.text , tz_offset); + + BEGIN + RETURN cast(v_string as sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + + +CREATE OR REPLACE FUNCTION sys.TODATETIMEOFFSET(IN input_expr PG_CATALOG.TEXT , IN tz_offset anyelement) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + v_string pg_catalog.text; + v_sign pg_catalog.text; + hr INTEGER; + mi INTEGER; + tz_sign INTEGER; + tz_offset_smallint INTEGER; + input_expr_datetime2 datetime2; +BEGIN + + BEGIN + input_expr_datetime2:= cast(input_expr as sys.datetime2); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + + IF pg_typeof(tz_offset) NOT 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 ,'varbinary'::regtype) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + BEGIN + IF pg_typeof(tz_offset) NOT IN ('varbinary'::regtype) THEN + tz_offset := FLOOR(tz_offset); + END IF; + tz_offset_smallint := cast(tz_offset AS smallint); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Arithmetic overflow error converting expression to data type smallint.'; + END; + + IF input_expr IS NULL THEN + RETURN NULL; + END IF; + + IF tz_offset_smallint < 0 THEN + tz_sign := 1; + ELSE + tz_sign := 0; + END IF; + + IF tz_offset_smallint > 840 or tz_offset_smallint < -840 THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + hr := tz_offset_smallint / 60; + mi := tz_offset_smallint % 60; + + v_sign := ( + SELECT CASE + WHEN (tz_sign) = 1 + THEN '-' + WHEN (tz_sign) = 0 + THEN '+' + END + ); + + + v_string := CONCAT(input_expr_datetime2::pg_catalog.text,v_sign,abs(hr)::SMALLINT::text,':', + abs(mi)::SMALLINT::text); + + BEGIN + RETURN cast(v_string as sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + + CREATE OR REPLACE FUNCTION sys.datetime2fromparts(IN p_year TEXT, IN p_month TEXT, IN p_day TEXT, @@ -540,21 +702,10 @@ RETURNS INTEGER AS 'babelfishpg_tsql', 'object_id' LANGUAGE C STABLE; -CREATE OR REPLACE FUNCTION sys.parsename ( - object_name VARCHAR - ,object_piece INT - ) -RETURNS VARCHAR AS $$ -/*************************************************************** -EXTENSION PACK function PARSENAME(x) -***************************************************************/ -SELECT CASE - WHEN char_length($1) < char_length(pg_catalog.replace($1, '.', '')) + 4 - AND $2 BETWEEN 1 - AND 4 - THEN reverse(split_part(reverse($1), '.', $2)) - ELSE NULL - END $$ immutable LANGUAGE 'sql'; +CREATE OR REPLACE FUNCTION sys.parsename(object_name sys.VARCHAR, object_piece int) +RETURNS sys.SYSNAME +AS 'babelfishpg_tsql', 'parsename' +LANGUAGE C IMMUTABLE STRICT; CREATE OR REPLACE FUNCTION sys.timefromparts(IN p_hour NUMERIC, IN p_minute NUMERIC, @@ -579,7 +730,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 +739,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, @@ -655,6 +806,19 @@ CREATE OR REPLACE FUNCTION sys.has_dbaccess(database_name SYSNAME) RETURNS INTEG 'babelfishpg_tsql', 'has_dbaccess' LANGUAGE C STABLE STRICT; +-- This function performs string rewriting for the full text search CONTAINS predicate +-- in Babelfish +-- For example, a T-SQL query +-- SELECT * FROM t WHERE CONTAINS(txt, '"good old days"') +-- is rewritten into a Postgres query +-- SELECT * FROM t WHERE to_tsvector('fts_contains', txt) @@ to_tsquery('fts_contains', 'good <-> old <-> days') +-- In particular, the string constant '"good old days"' gets rewritten into 'good <-> old <-> days' +-- This function performs the string rewriting from '"good old days"' to 'good <-> old <-> days' +-- For prefix terms, '"word1*"' is rewritten into 'word1:*', and '"word1 word2 word3*"' is rewritten into 'word1<->word2<->word3:*' +CREATE OR REPLACE FUNCTION sys.babelfish_fts_rewrite(IN phrase text) RETURNS TEXT AS +'babelfishpg_tsql', 'babelfish_fts_rewrite' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + CREATE OR REPLACE FUNCTION sys.datefromparts(IN year INT, IN month INT, IN day INT) RETURNS DATE AS $BODY$ @@ -720,7 +884,7 @@ BEGIN RAISE most_specific_type_mismatch; -- Check if arguments are out of range - ELSIF ((p_year NOT BETWEEN 1753 AND 9999) OR + ELSIF ((p_year NOT BETWEEN 0001 AND 9999) OR (p_month NOT BETWEEN 1 AND 12) OR (p_day NOT BETWEEN 1 AND 31) OR (p_hour NOT BETWEEN 0 AND 23) OR @@ -758,7 +922,12 @@ BEGIN ); v_string := CONCAT(v_resdatetime::pg_catalog.text,v_sign,abs(p_hour_offset)::SMALLINT::text,':', abs(p_minute_offset)::SMALLINT::text); - RETURN CAST(v_string AS sys.DATETIMEOFFSET); + BEGIN + RETURN cast(v_string AS sys.datetimeoffset); + exception + WHEN others THEN + RAISE invalid_datetime_format; + END; EXCEPTION WHEN most_specific_type_mismatch THEN RAISE USING MESSAGE := 'Scale argument is not valid. Valid expressions for data type datetimeoffset scale argument are integer constants and integer constant expressions', @@ -779,6 +948,392 @@ $BODY$ LANGUAGE plpgsql IMMUTABLE; +CREATE OR REPLACE FUNCTION sys.SMALLDATETIMEFROMPARTS(IN p_year INTEGER, + IN p_month INTEGER, + IN p_day INTEGER, + IN p_hour INTEGER, + IN p_minute INTEGER + ) +RETURNS sys.smalldatetime +AS +$BODY$ +DECLARE + v_ressmalldatetime TIMESTAMP WITHOUT TIME ZONE; + v_string pg_catalog.text; + p_seconds INTEGER; +BEGIN + IF p_year IS NULL OR p_month is NULL OR p_day IS NULL OR p_hour IS NULL OR p_minute IS NULL THEN + RETURN NULL; + END IF; + + -- Check if arguments are out of range + IF ((p_year NOT BETWEEN 1900 AND 2079) OR + (p_month NOT BETWEEN 1 AND 12) OR + (p_day NOT BETWEEN 1 AND 31) OR + (p_hour NOT BETWEEN 0 AND 23) OR + (p_minute NOT BETWEEN 0 AND 59) OR (p_year = 2079 AND p_month > 6) OR (p_year = 2079 AND p_month = 6 AND p_day > 6)) + THEN + RAISE invalid_datetime_format; + END IF; + p_seconds := 0; + v_ressmalldatetime := make_timestamp(p_year, + p_month, + p_day, + p_hour, + p_minute, + p_seconds); + + v_string := v_ressmalldatetime::pg_catalog.text; + RETURN CAST(v_string AS sys.SMALLDATETIME); +EXCEPTION + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type smalldatetime, 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.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +create or replace function sys.babelfish_timezone_mapping(IN tmz text) returns text +AS 'babelfishpg_tsql', 'timezone_mapping' +LANGUAGE C IMMUTABLE ; + +CREATE OR REPLACE FUNCTION sys.timezone(IN tzzone PG_CATALOG.TEXT , IN input_expr PG_CATALOG.TEXT) +RETURNS sys.datetimeoffset +AS +$BODY$ +BEGIN + IF input_expr = 'NULL' THEN + RAISE USING MESSAGE := 'Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.'; + END IF; + + IF input_expr IS NULL OR tzzone IS NULL THEN + RETURN NULL; + END IF; + + RAISE USING MESSAGE := 'Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.timezone(IN tzzone PG_CATALOG.TEXT , IN input_expr anyelement) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + tz_offset PG_CATALOG.TEXT; + tz_name PG_CATALOG.TEXT; + lower_tzn PG_CATALOG.TEXT; + prev_res PG_CATALOG.TEXT; + result PG_CATALOG.TEXT; + is_dstt bool; + tz_diff PG_CATALOG.TEXT; + input_expr_tx PG_CATALOG.TEXT; + input_expr_tmz TIMESTAMPTZ; +BEGIN + IF input_expr IS NULL OR tzzone IS NULL THEN + RETURN NULL; + END IF; + + lower_tzn := lower(tzzone); + IF lower_tzn <> 'utc' THEN + tz_name := sys.babelfish_timezone_mapping(lower_tzn); + ELSE + tz_name := 'utc'; + END IF; + + IF tz_name = 'NULL' THEN + RAISE USING MESSAGE := format('Argument data type or the parameter %s provided to AT TIME ZONE clause is invalid.', tzzone); + END IF; + + IF pg_typeof(input_expr) IN ('sys.smalldatetime'::regtype, 'sys.datetime'::regtype, 'sys.datetime2'::regtype) THEN + input_expr_tx := input_expr::TEXT; + input_expr_tmz := input_expr_tx :: TIMESTAMPTZ; + + result := (SELECT input_expr_tmz AT TIME ZONE tz_name)::TEXT; + tz_diff := (SELECT result::TIMESTAMPTZ - input_expr_tmz)::TEXT; + if LEFT(tz_diff,1) <> '-' THEN + tz_diff := concat('+',tz_diff); + END IF; + tz_offset := left(tz_diff,6); + input_expr_tx := concat(input_expr_tx,tz_offset); + return cast(input_expr_tx as sys.datetimeoffset); + ELSIF pg_typeof(input_expr) = 'sys.DATETIMEOFFSET'::regtype THEN + input_expr_tx := input_expr::TEXT; + input_expr_tmz := input_expr_tx :: TIMESTAMPTZ; + result := (SELECT input_expr_tmz AT TIME ZONE tz_name)::TEXT; + tz_diff := (SELECT result::TIMESTAMPTZ - input_expr_tmz)::TEXT; + if LEFT(tz_diff,1) <> '-' THEN + tz_diff := concat('+',tz_diff); + END IF; + tz_offset := left(tz_diff,6); + result := concat(result,tz_offset); + return cast(result as sys.datetimeoffset); + ELSE + RAISE USING MESSAGE := 'Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.'; + END IF; + +END; +$BODY$ +LANGUAGE 'plpgsql' STABLE; + +CREATE OR REPLACE FUNCTION sys.typeproperty( + typename sys.VARCHAR, + property sys.VARCHAR + ) +RETURNS INT +AS $$ +DECLARE +BEGIN + RETURN NULL; +END; +$$ +LANGUAGE plpgsql STABLE; + + +CREATE OR REPLACE FUNCTION sys.SWITCHOFFSET(IN input_expr PG_CATALOG.TEXT, + IN tz_offset PG_CATALOG.TEXT) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + p_year INTEGER; + p_month INTEGER; + p_day INTEGER; + p_hour INTEGER; + p_minute INTEGER; + p_seconds INTEGER; + p_nanosecond PG_CATALOG.TEXT; + p_tzoffset INTEGER; + f_tzoffset INTEGER; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + offset_str PG_CATALOG.TEXT; + v_resdatetimeupdated TIMESTAMP WITHOUT TIME ZONE; + tzfm INTEGER; + str_hr PG_CATALOG.TEXT; + str_mi PG_CATALOG.TEXT; + v_hr INTEGER; + v_mi INTEGER; + sign_flag INTEGER; + v_string pg_catalog.text; + isoverflow pg_catalog.text; +BEGIN + + BEGIN + p_year := date_part('year',input_expr::TIMESTAMP); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + if p_year <1 or p_year > 9999 THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END IF; + + + BEGIN + input_expr:= cast(input_expr AS datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + IF input_expr IS NULL or tz_offset IS NULL THEN + RETURN NULL; + END IF; + + + IF tz_offset LIKE '+__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := 1; + ELSIF tz_offset LIKE '-__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := -1; + ELSE + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + + + BEGIN + v_hr := str_hr::INTEGER; + v_mi := str_mi::INTEGER; + exception + WHEN others THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END; + + if v_hr > 14 or (v_hr = 14 and v_mi > 0) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + tzfm := sign_flag*((v_hr*60)+v_mi); + + p_year := date_part('year',input_expr::TIMESTAMP); + p_month := date_part('month',input_expr::TIMESTAMP); + p_day := date_part('day',input_expr::TIMESTAMP); + p_hour := date_part('hour',input_expr::TIMESTAMP); + p_minute := date_part('minute',input_expr::TIMESTAMP); + p_seconds := TRUNC(date_part('second', input_expr::TIMESTAMP))::INTEGER; + p_tzoffset := -1*sys.babelfish_get_datetimeoffset_tzoffset(cast(input_expr as sys.datetimeoffset))::integer; + + p_nanosecond := split_part(input_expr COLLATE "C",'.',2); + p_nanosecond := split_part(p_nanosecond COLLATE "C",' ',1); + + + f_tzoffset := p_tzoffset + tzfm; + + v_resdatetime := make_timestamp(p_year,p_month,p_day,p_hour,p_minute,p_seconds); + v_resdatetimeupdated := v_resdatetime + make_interval(mins => f_tzoffset); + + isoverflow := split_part(v_resdatetimeupdated::TEXT COLLATE "C",' ',3); + + v_string := CONCAT(v_resdatetimeupdated::pg_catalog.text,'.',p_nanosecond::text,tz_offset); + p_year := split_part(v_string COLLATE "C",'-',1)::INTEGER; + + + if p_year <1 or p_year > 9999 or isoverflow = 'BC' THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.'; + END IF; + + BEGIN + RETURN cast(v_string AS sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.SWITCHOFFSET(IN input_expr PG_CATALOG.TEXT, + IN tz_offset anyelement) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + p_year INTEGER; + p_month INTEGER; + p_day INTEGER; + p_hour INTEGER; + p_minute INTEGER; + p_seconds INTEGER; + p_nanosecond PG_CATALOG.TEXT; + p_tzoffset INTEGER; + f_tzoffset INTEGER; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + offset_str PG_CATALOG.TEXT; + v_resdatetimeupdated TIMESTAMP WITHOUT TIME ZONE; + tzfm INTEGER; + str_hr PG_CATALOG.TEXT; + str_mi PG_CATALOG.TEXT; + v_hr INTEGER; + v_mi INTEGER; + sign_flag INTEGER; + v_string pg_catalog.text; + v_sign PG_CATALOG.TEXT; + tz_offset_smallint smallint; + isoverflow pg_catalog.text; +BEGIN + + IF pg_typeof(tz_offset) NOT 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,'varbinary'::regtype ) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + BEGIN + p_year := date_part('year',input_expr::TIMESTAMP); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + + if p_year <1 or p_year > 9999 THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END IF; + + BEGIN + input_expr:= cast(input_expr AS datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + BEGIN + IF pg_typeof(tz_offset) NOT IN ('varbinary'::regtype) THEN + tz_offset := FLOOR(tz_offset); + END IF; + tz_offset_smallint := cast(tz_offset AS smallint); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Arithmetic overflow error converting expression to data type smallint.'; + END; + + IF input_expr IS NULL THEN + RETURN NULL; + END IF; + + if tz_offset_smallint > 840 or tz_offset_smallint < -840 THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + v_hr := tz_offset_smallint/60; + v_mi := tz_offset_smallint%60; + + + p_year := date_part('year',input_expr::TIMESTAMP); + p_month := date_part('month',input_expr::TIMESTAMP); + p_day := date_part('day',input_expr::TIMESTAMP); + p_hour := date_part('hour',input_expr::TIMESTAMP); + p_minute := date_part('minute',input_expr::TIMESTAMP); + p_seconds := TRUNC(date_part('second', input_expr::TIMESTAMP))::INTEGER; + p_tzoffset := -1*sys.babelfish_get_datetimeoffset_tzoffset(cast(input_expr as sys.datetimeoffset))::integer; + + v_sign := ( + SELECT CASE + WHEN (tz_offset_smallint) >= 0 + THEN '+' + ELSE '-' + END + ); + + p_nanosecond := split_part(input_expr COLLATE "C",'.',2); + p_nanosecond := split_part(p_nanosecond COLLATE "C",' ',1); + + f_tzoffset := p_tzoffset + tz_offset_smallint; + v_resdatetime := make_timestamp(p_year,p_month,p_day,p_hour,p_minute,p_seconds); + v_resdatetimeupdated := v_resdatetime + make_interval(mins => f_tzoffset); + + isoverflow := split_part(v_resdatetimeupdated::TEXT COLLATE "C",' ',3); + + v_string := CONCAT(v_resdatetimeupdated::pg_catalog.text,'.',p_nanosecond::text,v_sign,abs(v_hr)::TEXT,':',abs(v_mi)::TEXT); + + p_year := split_part(v_string COLLATE "C",'-',1)::INTEGER; + + if p_year <1 or p_year > 9999 or isoverflow = 'BC' THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.'; + END IF; + + + BEGIN + RETURN cast(v_string AS sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + -- Duplicate functions with arg TEXT since ANYELEMNT cannot handle type unknown. CREATE OR REPLACE FUNCTION sys.stuff(expr TEXT, start INTEGER, length INTEGER, replace_expr TEXT) RETURNS TEXT AS @@ -1001,7 +1556,7 @@ CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdat AS $body$ BEGIN - return CAST(sys.datediff_internal_date(datepart, startdate, enddate) AS INTEGER); + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1010,7 +1565,7 @@ CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdat AS $body$ BEGIN - return CAST(sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP) AS INTEGER); + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1019,7 +1574,7 @@ CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdat AS $body$ BEGIN - return CAST(sys.datediff_internal_df(datepart, startdate, enddate) AS INTEGER); + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1028,7 +1583,7 @@ CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdat AS $body$ BEGIN - return CAST(sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP) AS INTEGER); + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1037,7 +1592,7 @@ CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdat AS $body$ BEGIN - return CAST(sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP) AS INTEGER); + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1046,7 +1601,7 @@ CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdat AS $body$ BEGIN - return CAST(sys.datediff_internal(datepart, startdate, enddate) AS INTEGER); + return sys.datediff_internal(datepart, startdate, enddate); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1056,7 +1611,7 @@ CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN star AS $body$ BEGIN - return sys.datediff_internal_date(datepart, startdate, enddate); + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1065,7 +1620,7 @@ CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN star AS $body$ BEGIN - return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1074,7 +1629,7 @@ CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN star AS $body$ BEGIN - return sys.datediff_internal_df(datepart, startdate, enddate); + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1083,7 +1638,7 @@ CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN star AS $body$ BEGIN - return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1092,7 +1647,7 @@ CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN star AS $body$ BEGIN - return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1101,7 +1656,7 @@ CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN star AS $body$ BEGIN - return sys.datediff_internal(datepart, startdate, enddate); + return sys.datediff_internal_big(datepart, startdate, enddate); END $body$ LANGUAGE plpgsql IMMUTABLE; @@ -1126,6 +1681,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 + 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 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$ @@ -1141,13 +1733,83 @@ 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,'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; + + 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; 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; @@ -1221,390 +1883,61 @@ LANGUAGE plpgsql IMMUTABLE; 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 $$ -BEGIN - 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; -$$ +CREATE OR REPLACE FUNCTION sys.dateadd_internal_df(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate datetimeoffset) +RETURNS datetimeoffset AS +'babelfishpg_common', 'dateadd_datetimeoffset' STRICT -LANGUAGE plpgsql IMMUTABLE; +LANGUAGE C IMMUTABLE PARALLEL SAFE; CREATE OR REPLACE FUNCTION sys.dateadd_internal(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS ANYELEMENT AS $$ BEGIN - IF pg_typeof(startdate) = 'date'::regtype AND - datepart IN ('hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond') THEN - RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type date.', datepart; + IF pg_typeof(startdate) = 'time'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 0); END IF; - IF pg_typeof(startdate) = 'time'::regtype AND - datepart IN ('year', 'quarter', 'month', 'doy', 'day', 'week', 'weekday') THEN - RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type time.', datepart; - END IF; - - CASE datepart - WHEN 'year' THEN - RETURN startdate + make_interval(years => num); - WHEN 'quarter' THEN - RETURN startdate + make_interval(months => num * 3); - WHEN 'month' THEN - RETURN startdate + make_interval(months => num); - WHEN 'dayofyear', 'y' THEN - RETURN startdate + make_interval(days => num); - WHEN 'day' THEN - RETURN startdate + make_interval(days => num); - WHEN 'week' THEN - RETURN startdate + make_interval(weeks => num); - WHEN 'weekday' THEN - RETURN startdate + make_interval(days => num); - WHEN 'hour' THEN - RETURN startdate + make_interval(hours => num); - WHEN 'minute' THEN - RETURN startdate + make_interval(mins => num); - WHEN 'second' THEN - RETURN startdate + make_interval(secs => num); - WHEN 'millisecond' THEN - RETURN startdate + make_interval(secs => (num::numeric) * 0.001); - WHEN 'microsecond' THEN - IF pg_typeof(startdate) = 'time'::regtype THEN - RETURN startdate + make_interval(secs => (num::numeric) * 0.000001); - ELSIF pg_typeof(startdate) = 'sys.datetime2'::regtype THEN - RETURN startdate + make_interval(secs => (num::numeric) * 0.000001); - ELSIF pg_typeof(startdate) = 'sys.smalldatetime'::regtype THEN - RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type smalldatetime.', datepart; - ELSE - RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type datetime.', datepart; - END IF; - WHEN 'nanosecond' THEN - IF pg_typeof(startdate) = 'time'::regtype THEN - RETURN startdate + make_interval(secs => TRUNC((num::numeric)* 0.000000001, 6)); - ELSIF pg_typeof(startdate) = 'sys.datetime2'::regtype THEN - RETURN startdate + make_interval(secs => TRUNC((num::numeric)* 0.000000001, 6)); - ELSIF pg_typeof(startdate) = 'sys.smalldatetime'::regtype THEN - RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type smalldatetime.', datepart; - ELSE - RAISE EXCEPTION 'The datepart % is not supported by date function dateadd for data type datetime.', datepart; - END IF; - ELSE - RAISE EXCEPTION '''%'' is not a recognized dateadd option.', datepart; - END CASE; -END; -$$ -STRICT -LANGUAGE plpgsql IMMUTABLE; - -CREATE OR REPLACE FUNCTION sys.datediff_internal_df(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) RETURNS BIGINT AS $$ -DECLARE - result BIGINT; - year_diff BIGINT; - month_diff BIGINT; - day_diff BIGINT; - hour_diff BIGINT; - minute_diff BIGINT; - second_diff BIGINT; - millisecond_diff BIGINT; - microsecond_diff BIGINT; - y1 BIGINT; - m1 BIGINT; - d1 BIGINT; - y2 BIGINT; - m2 BIGINT; - d2 BIGINT; -BEGIN - CASE datepart - WHEN 'year' THEN - year_diff = sys.datepart('year', enddate) - sys.datepart('year', startdate); - result = year_diff; - WHEN 'quarter' THEN - year_diff = sys.datepart('year', enddate) - sys.datepart('year', startdate); - month_diff = sys.datepart('month', enddate) - sys.datepart('month', startdate); - result = (year_diff * 12 + month_diff) / 3; - WHEN 'month' THEN - year_diff = sys.datepart('year', enddate) - sys.datepart('year', startdate); - month_diff = sys.datepart('month', enddate) - sys.datepart('month', startdate); - result = year_diff * 12 + month_diff; - WHEN 'doy', 'y' THEN - day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); - result = day_diff; - WHEN 'day' THEN - y1 = sys.datepart('year', enddate); - m1 = sys.datepart('month', enddate); - d1 = sys.datepart('day', enddate); - y2 = sys.datepart('year', startdate); - m2 = sys.datepart('month', startdate); - d2 = sys.datepart('day', startdate); - result = sys.num_days_in_date(d1, m1, y1) - sys.num_days_in_date(d2, m2, y2); - WHEN 'week' THEN - day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); - result = day_diff / 7; - WHEN 'hour' THEN - y1 = sys.datepart('year', enddate); - m1 = sys.datepart('month', enddate); - d1 = sys.datepart('day', enddate); - y2 = sys.datepart('year', startdate); - m2 = sys.datepart('month', startdate); - d2 = sys.datepart('day', startdate); - day_diff = sys.num_days_in_date(d1, m1, y1) - sys.num_days_in_date(d2, m2, y2); - hour_diff = sys.datepart('hour', enddate) - sys.datepart('hour', startdate); - result = day_diff * 24 + hour_diff; - WHEN 'minute' THEN - day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); - hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) startdate); - minute_diff = sys.datepart('minute', enddate OPERATOR(sys.-) startdate); - result = (day_diff * 24 + hour_diff) * 60 + minute_diff; - WHEN 'second' THEN - day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); - hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) startdate); - minute_diff = sys.datepart('minute', enddate OPERATOR(sys.-) startdate); - second_diff = TRUNC(sys.datepart('second', enddate OPERATOR(sys.-) startdate)); - result = ((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60 + second_diff; - WHEN 'millisecond' THEN - -- millisecond result from date_part by default contains second value, - -- so we do not need to add second_diff again - day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); - hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) startdate); - minute_diff = sys.datepart('minute', enddate OPERATOR(sys.-) startdate); - second_diff = TRUNC(sys.datepart('second', enddate OPERATOR(sys.-) startdate)); - millisecond_diff = TRUNC(sys.datepart('millisecond', enddate OPERATOR(sys.-) startdate)); - result = (((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60) * 1000 + millisecond_diff; - WHEN 'microsecond' THEN - -- microsecond result from date_part by default contains second and millisecond values, - -- so we do not need to add second_diff and millisecond_diff again - day_diff = sys.datepart('day', enddate OPERATOR(sys.-) startdate); - hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) startdate); - minute_diff = sys.datepart('minute', enddate OPERATOR(sys.-) startdate); - second_diff = TRUNC(sys.datepart('second', enddate OPERATOR(sys.-) startdate)); - millisecond_diff = TRUNC(sys.datepart('millisecond', enddate OPERATOR(sys.-) startdate)); - microsecond_diff = TRUNC(sys.datepart('microsecond', enddate OPERATOR(sys.-) startdate)); - result = ((((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60) * 1000) * 1000 + microsecond_diff; - WHEN 'nanosecond' THEN - -- Best we can do - Postgres does not support nanosecond precision - day_diff = sys.datepart('day', enddate - startdate); - hour_diff = sys.datepart('hour', enddate OPERATOR(sys.-) startdate); - minute_diff = sys.datepart('minute', enddate OPERATOR(sys.-) startdate); - second_diff = TRUNC(sys.datepart('second', enddate OPERATOR(sys.-) startdate)); - millisecond_diff = TRUNC(sys.datepart('millisecond', enddate OPERATOR(sys.-) startdate)); - microsecond_diff = TRUNC(sys.datepart('microsecond', enddate OPERATOR(sys.-) startdate)); - result = (((((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60) * 1000) * 1000 + microsecond_diff) * 1000; - ELSE - RAISE EXCEPTION '"%" is not a recognized datediff option.', datepart; - END CASE; - - return result; -END; -$$ -STRICT -LANGUAGE plpgsql IMMUTABLE; - -CREATE OR REPLACE FUNCTION sys.datediff_internal_date(IN datepart PG_CATALOG.TEXT, IN startdate PG_CATALOG.date, IN enddate PG_CATALOG.date) RETURNS BIGINT AS $$ -DECLARE - result BIGINT; - year_diff BIGINT; - month_diff BIGINT; - day_diff BIGINT; - hour_diff BIGINT; - minute_diff BIGINT; - second_diff BIGINT; - millisecond_diff BIGINT; - microsecond_diff BIGINT; -BEGIN - CASE datepart - WHEN 'year' THEN - year_diff = date_part('year', enddate)::BIGINT - date_part('year', startdate)::BIGINT; - result = year_diff; - WHEN 'quarter' THEN - year_diff = date_part('year', enddate)::BIGINT - date_part('year', startdate)::BIGINT; - month_diff = date_part('month', enddate)::BIGINT - date_part('month', startdate)::BIGINT; - result = (year_diff * 12 + month_diff) / 3; - WHEN 'month' THEN - year_diff = date_part('year', enddate)::BIGINT - date_part('year', startdate)::BIGINT; - month_diff = date_part('month', enddate)::BIGINT - date_part('month', startdate)::BIGINT; - result = year_diff * 12 + month_diff; - -- for all intervals smaller than month, (DATE - DATE) already returns the integer number of days - -- between the dates, so just use that directly as the day_diff. There is no finer resolution - -- than days with the DATE type anyways. - WHEN 'doy', 'y' THEN - day_diff = enddate - startdate; - result = day_diff; - WHEN 'day' THEN - day_diff = enddate - startdate; - result = day_diff; - WHEN 'week' THEN - day_diff = enddate - startdate; - result = day_diff / 7; - WHEN 'hour' THEN - day_diff = enddate - startdate; - result = day_diff * 24; - WHEN 'minute' THEN - day_diff = enddate - startdate; - result = day_diff * 24 * 60; - WHEN 'second' THEN - day_diff = enddate - startdate; - result = day_diff * 24 * 60 * 60; - WHEN 'millisecond' THEN - -- millisecond result from date_part by default contains second value, - -- so we do not need to add second_diff again - day_diff = enddate - startdate; - result = day_diff * 24 * 60 * 60 * 1000; - WHEN 'microsecond' THEN - -- microsecond result from date_part by default contains second and millisecond values, - -- so we do not need to add second_diff and millisecond_diff again - day_diff = enddate - startdate; - result = day_diff * 24 * 60 * 60 * 1000 * 1000; - WHEN 'nanosecond' THEN - -- Best we can do - Postgres does not support nanosecond precision - day_diff = enddate - startdate; - result = day_diff * 24 * 60 * 60 * 1000 * 1000 * 1000; - ELSE - RAISE EXCEPTION '"%" is not a recognized datediff option.', datepart; - END CASE; - - return result; -END; -$$ -STRICT -LANGUAGE plpgsql IMMUTABLE; - -CREATE OR REPLACE FUNCTION sys.datediff_internal(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) RETURNS BIGINT AS $$ -DECLARE - result BIGINT; - year_diff BIGINT; - month_diff BIGINT; - day_diff BIGINT; - hour_diff BIGINT; - minute_diff BIGINT; - second_diff BIGINT; - millisecond_diff BIGINT; - microsecond_diff BIGINT; - y1 BIGINT; - m1 BIGINT; - d1 BIGINT; - y2 BIGINT; - m2 BIGINT; - d2 BIGINT; -BEGIN - CASE datepart - WHEN 'year' THEN - year_diff = date_part('year', enddate)::BIGINT - date_part('year', startdate)::BIGINT; - result = year_diff; - WHEN 'quarter' THEN - year_diff = date_part('year', enddate)::BIGINT - date_part('year', startdate)::BIGINT; - month_diff = date_part('month', enddate)::BIGINT - date_part('month', startdate)::BIGINT; - result = (year_diff * 12 + month_diff) / 3; - WHEN 'month' THEN - year_diff = date_part('year', enddate)::BIGINT - date_part('year', startdate)::BIGINT; - month_diff = date_part('month', enddate)::BIGINT - date_part('month', startdate)::BIGINT; - result = year_diff * 12 + month_diff; - WHEN 'doy', 'y' THEN - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - result = day_diff; - WHEN 'day' THEN - y1 = date_part('year', enddate)::BIGINT; - m1 = date_part('month', enddate)::BIGINT; - d1 = date_part('day', enddate)::BIGINT; - y2 = date_part('year', startdate)::BIGINT; - m2 = date_part('month', startdate)::BIGINT; - d2 = date_part('day', startdate)::BIGINT; - result = sys.num_days_in_date(d1, m1, y1) - sys.num_days_in_date(d2, m2, y2); - WHEN 'week' THEN - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - result = day_diff / 7; - WHEN 'hour' THEN - y1 = date_part('year', enddate)::BIGINT; - m1 = date_part('month', enddate)::BIGINT; - d1 = date_part('day', enddate)::BIGINT; - y2 = date_part('year', startdate)::BIGINT; - m2 = date_part('month', startdate)::BIGINT; - d2 = date_part('day', startdate)::BIGINT; - day_diff = sys.num_days_in_date(d1, m1, y1) - sys.num_days_in_date(d2, m2, y2); - hour_diff = date_part('hour', enddate)::BIGINT - date_part('hour', startdate)::BIGINT; - result = day_diff * 24 + hour_diff; - WHEN 'minute' THEN - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::BIGINT; - minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::BIGINT; - result = (day_diff * 24 + hour_diff) * 60 + minute_diff; - WHEN 'second' THEN - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::BIGINT; - minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::BIGINT; - second_diff = TRUNC(date_part('second', enddate OPERATOR(sys.-) startdate)); - result = ((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60 + second_diff; - WHEN 'millisecond' THEN - -- millisecond result from date_part by default contains second value, - -- so we do not need to add second_diff again - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::BIGINT; - minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::BIGINT; - second_diff = TRUNC(date_part('second', enddate OPERATOR(sys.-) startdate)); - millisecond_diff = TRUNC(date_part('millisecond', enddate OPERATOR(sys.-) startdate)); - result = (((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60) * 1000 + millisecond_diff; - WHEN 'microsecond' THEN - -- microsecond result from date_part by default contains second and millisecond values, - -- so we do not need to add second_diff and millisecond_diff again - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::BIGINT; - minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::BIGINT; - second_diff = TRUNC(date_part('second', enddate OPERATOR(sys.-) startdate)); - millisecond_diff = TRUNC(date_part('millisecond', enddate OPERATOR(sys.-) startdate)); - microsecond_diff = TRUNC(date_part('microsecond', enddate OPERATOR(sys.-) startdate)); - result = ((((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60) * 1000) * 1000 + microsecond_diff; - WHEN 'nanosecond' THEN - -- Best we can do - Postgres does not support nanosecond precision - day_diff = date_part('day', enddate OPERATOR(sys.-) startdate)::BIGINT; - hour_diff = date_part('hour', enddate OPERATOR(sys.-) startdate)::BIGINT; - minute_diff = date_part('minute', enddate OPERATOR(sys.-) startdate)::BIGINT; - second_diff = TRUNC(date_part('second', enddate OPERATOR(sys.-) startdate)); - millisecond_diff = TRUNC(date_part('millisecond', enddate OPERATOR(sys.-) startdate)); - microsecond_diff = TRUNC(date_part('microsecond', enddate OPERATOR(sys.-) startdate)); - result = (((((day_diff * 24 + hour_diff) * 60 + minute_diff) * 60) * 1000) * 1000 + microsecond_diff) * 1000; - ELSE - RAISE EXCEPTION '"%" is not a recognized datediff option.', datepart; - END CASE; - - return result; + IF pg_typeof(startdate) = 'date'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 1); + END IF; + IF pg_typeof(startdate) = 'sys.smalldatetime'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 2); + END IF; + IF (pg_typeof(startdate) = 'sys.datetime'::regtype or pg_typeof(startdate) = 'timestamp'::regtype) THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 3); + END IF; + IF pg_typeof(startdate) = 'sys.datetime2'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 4); + END IF; END; $$ STRICT LANGUAGE plpgsql IMMUTABLE; +CREATE OR REPLACE FUNCTION sys.dateadd_internal_datetime(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT, IN datetimetype INT) +RETURNS TIMESTAMP AS +'babelfishpg_common', 'dateadd_datetime' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datediff_internal_big(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) +RETURNS BIGINT AS +'babelfishpg_common', 'timestamp_diff_big' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datediff_internal(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) +RETURNS INT AS +'babelfishpg_common', 'timestamp_diff' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + 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::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 @@ -1629,12 +1962,6 @@ $BODY$ STRICT LANGUAGE sql IMMUTABLE; -CREATE OR REPLACE FUNCTION sys.GETUTCDATE() RETURNS sys.DATETIME AS -$BODY$ -SELECT CAST(CURRENT_TIMESTAMP AT TIME ZONE 'UTC'::pg_catalog.text AS sys.DATETIME); -$BODY$ -LANGUAGE SQL STABLE PARALLEL SAFE; - -- These come from the built-in pg_catalog.count in pg_aggregate.dat CREATE AGGREGATE sys.count(*) ( @@ -1707,6 +2034,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; @@ -1731,6 +2061,17 @@ 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) +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; + -- 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() @@ -1781,8 +2122,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; @@ -1834,6 +2175,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$ @@ -1908,61 +2285,6 @@ CREATE OR REPLACE FUNCTION sys.db_name() RETURNS sys.nvarchar(128) AS 'babelfishpg_tsql', 'babelfish_db_name' LANGUAGE C PARALLEL SAFE IMMUTABLE; --- BABEL-1783: (partial) support for sys.fn_listextendedproperty -create table if not exists sys.extended_properties ( -class sys.tinyint, -class_desc sys.nvarchar(60), -major_id int, -minor_id int, -name sys.sysname, -value sys.sql_variant -); -GRANT SELECT ON sys.extended_properties TO PUBLIC; - -CREATE OR REPLACE FUNCTION sys.fn_listextendedproperty ( -property_name varchar(128), -level0_object_type varchar(128), -level0_object_name varchar(128), -level1_object_type varchar(128), -level1_object_name varchar(128), -level2_object_type varchar(128), -level2_object_name varchar(128) -) -returns table ( -objtype sys.sysname, -objname sys.sysname, -name sys.sysname, -value sys.sql_variant -) -as $$ -begin --- currently only support COLUMN property -IF (((SELECT coalesce(property_name COLLATE sys.database_default, '')) = '') or - ((SELECT UPPER(coalesce(property_name COLLATE sys.database_default, ''))) = 'COLUMN')) THEN - IF (((SELECT LOWER(coalesce(level0_object_type COLLATE sys.database_default, ''))) = 'schema') and - ((SELECT LOWER(coalesce(level1_object_type COLLATE sys.database_default, ''))) = 'table') and - ((SELECT LOWER(coalesce(level2_object_type COLLATE sys.database_default, ''))) = 'column')) THEN - RETURN query - select CAST('COLUMN' AS sys.sysname) as objtype, - CAST(t3.column_name AS sys.sysname) as objname, - t1.name as name, - t1.value as value - from sys.extended_properties t1, pg_catalog.pg_class t2, information_schema.columns t3 - where t1.major_id = t2.oid and - t2.relname = cast(t3.table_name as sys.sysname) COLLATE sys.database_default and - t2.relname = (SELECT coalesce(level1_object_name COLLATE sys.database_default, '')) COLLATE sys.database_default and - t3.column_name = (SELECT coalesce(level2_object_name COLLATE sys.database_default, '')) COLLATE sys.database_default; - END IF; -END IF; -RETURN; -end; -$$ -LANGUAGE plpgsql -STABLE; -GRANT EXECUTE ON FUNCTION sys.fn_listextendedproperty( - varchar(128), varchar(128), varchar(128), varchar(128), varchar(128), varchar(128), varchar(128) -) TO PUBLIC; - CREATE OR REPLACE FUNCTION sys.exp(IN arg DOUBLE PRECISION) RETURNS DOUBLE PRECISION AS 'babelfishpg_tsql', 'tsql_exp' @@ -2492,7 +2814,7 @@ BEGIN RETURN NULL; ELSIF (SELECT COUNT(nspname) FROM sys.babelfish_namespace_ext ext WHERE ext.orig_name = bbf_schema_name - AND CAST(ext.dbid AS oid) = CAST(sys.db_id() AS oid)) != 1 THEN + AND ext.dbid = sys.db_id()) != 1 THEN RETURN 0; END IF; END IF; @@ -2776,7 +3098,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; @@ -2823,7 +3146,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 ANYELEMENT, in escape bool) RETURNS sys.NVARCHAR AS $BODY$ @@ -2841,6 +3164,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 +3217,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 +3239,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 +3258,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; @@ -3115,122 +3445,15 @@ begin end if; end $body$ -LANGUAGE plpgsql STABLE PARALLEL SAFE STRICT; +LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE STRICT; CREATE OR REPLACE FUNCTION objectproperty( id INT, property SYS.VARCHAR ) -RETURNS INT -AS $$ -BEGIN - - IF NOT EXISTS(SELECT ao.object_id FROM sys.all_objects ao WHERE object_id = id) - THEN - RETURN NULL; - END IF; - - property := RTRIM(LOWER(COALESCE(property, ''))); - - IF property = 'ownerid' -- OwnerId - THEN - RETURN ( - SELECT CAST(COALESCE(t1.principal_id, pn.nspowner) AS INT) - FROM sys.all_objects t1 - INNER JOIN pg_catalog.pg_namespace pn ON pn.oid = t1.schema_id - WHERE t1.object_id = id); - - ELSEIF property = 'isdefaultcnst' -- IsDefaultCnst - THEN - RETURN (SELECT count(distinct dc.object_id) FROM sys.default_constraints dc WHERE dc.object_id = id); - - ELSEIF property = 'execisquotedidenton' -- ExecIsQuotedIdentOn - THEN - RETURN (SELECT CAST(sm.uses_quoted_identifier as int) FROM sys.all_sql_modules sm WHERE sm.object_id = id); - - ELSEIF property = 'tablefulltextpopulatestatus' -- TableFullTextPopulateStatus - THEN - IF NOT EXISTS (SELECT object_id FROM sys.tables t WHERE t.object_id = id) THEN - RETURN NULL; - END IF; - RETURN 0; - - ELSEIF property = 'tablehasvardecimalstorageformat' -- TableHasVarDecimalStorageFormat - THEN - IF NOT EXISTS (SELECT object_id FROM sys.tables t WHERE t.object_id = id) THEN - RETURN NULL; - END IF; - RETURN 0; - - ELSEIF property = 'ismsshipped' -- IsMSShipped - THEN - RETURN (SELECT CAST(ao.is_ms_shipped AS int) FROM sys.all_objects ao WHERE ao.object_id = id); - - ELSEIF property = 'isschemabound' -- IsSchemaBound - THEN - RETURN (SELECT CAST(sm.is_schema_bound AS int) FROM sys.all_sql_modules sm WHERE sm.object_id = id); - - ELSEIF property = 'execisansinullson' -- ExecIsAnsiNullsOn - THEN - RETURN (SELECT CAST(sm.uses_ansi_nulls AS int) FROM sys.all_sql_modules sm WHERE sm.object_id = id); - - ELSEIF property = 'isdeterministic' -- IsDeterministic - THEN - RETURN 0; - - ELSEIF property = 'isprocedure' -- IsProcedure - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type = 'P'); - - ELSEIF property = 'istable' -- IsTable - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type in ('IT', 'TT', 'U', 'S')); - - ELSEIF property = 'isview' -- IsView - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type = 'V'); - - ELSEIF property = 'isusertable' -- IsUserTable - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type = 'U' and is_ms_shipped = 0); - - ELSEIF property = 'istablefunction' -- IsTableFunction - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type in ('IF', 'TF', 'FT')); - - ELSEIF property = 'isinlinefunction' -- IsInlineFunction - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type in ('IF')); - - ELSEIF property = 'isscalarfunction' -- IsScalarFunction - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type in ('FN', 'FS')); - - ELSEIF property = 'isprimarykey' -- IsPrimaryKey - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type = 'PK'); - - ELSEIF property = 'isindexed' -- IsIndexed - THEN - RETURN (SELECT count(distinct object_id) from sys.indexes WHERE object_id = id and index_id > 0); - - ELSEIF property = 'isdefault' -- IsDefault - THEN - RETURN 0; - - ELSEIF property = 'isrule' -- IsRule - THEN - RETURN 0; - - ELSEIF property = 'istrigger' -- IsTrigger - THEN - RETURN (SELECT count(distinct object_id) from sys.all_objects WHERE object_id = id and type in ('TA', 'TR')); - END IF; - - RETURN NULL; -END; -$$ -LANGUAGE plpgsql STABLE; +RETURNS INT AS +'babelfishpg_tsql', 'objectproperty_internal' +LANGUAGE C STABLE; CREATE OR REPLACE FUNCTION OBJECTPROPERTYEX( id INT, @@ -3273,6 +3496,14 @@ 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.host_id() +RETURNS sys.VARCHAR(10) AS 'babelfishpg_tsql' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.host_id() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.identity_into_bigint(IN typename INT, IN seed BIGINT, IN increment BIGINT) +RETURNS bigint AS 'babelfishpg_tsql' LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.identity_into_bigint(INT, BIGINT, BIGINT) TO PUBLIC; + 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; @@ -3306,19 +3537,19 @@ RETURNS int AS 'babelfishpg_tsql','smallint_radians' LANGUAGE C STRICT IMMUTABL GRANT EXECUTE ON FUNCTION sys.radians(TINYINT) TO PUBLIC; CREATE OR REPLACE FUNCTION sys.power(IN arg1 BIGINT, IN arg2 NUMERIC) -RETURNS bigint AS 'babelfishpg_tsql','bigint_power' LANGUAGE C IMMUTABLE PARALLEL SAFE; +RETURNS bigint AS 'babelfishpg_tsql','bigint_power' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.power(BIGINT,NUMERIC) TO PUBLIC; CREATE OR REPLACE FUNCTION sys.power(IN arg1 INT, IN arg2 NUMERIC) -RETURNS int AS 'babelfishpg_tsql','int_power' LANGUAGE C IMMUTABLE PARALLEL SAFE; +RETURNS int AS 'babelfishpg_tsql','int_power' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.power(INT,NUMERIC) TO PUBLIC; CREATE OR REPLACE FUNCTION sys.power(IN arg1 SMALLINT, IN arg2 NUMERIC) -RETURNS int AS 'babelfishpg_tsql','smallint_power' LANGUAGE C IMMUTABLE PARALLEL SAFE; +RETURNS int AS 'babelfishpg_tsql','smallint_power' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.power(SMALLINT,NUMERIC) TO PUBLIC; CREATE OR REPLACE FUNCTION sys.power(IN arg1 TINYINT, IN arg2 NUMERIC) -RETURNS int AS 'babelfishpg_tsql','smallint_power' LANGUAGE C IMMUTABLE PARALLEL SAFE; +RETURNS int AS 'babelfishpg_tsql','smallint_power' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE; GRANT EXECUTE ON FUNCTION sys.power(TINYINT,NUMERIC) TO PUBLIC; CREATE OR REPLACE FUNCTION sys.degrees(IN arg1 NUMERIC) @@ -3434,9 +3665,529 @@ END; $$ LANGUAGE plpgsql STABLE; -CREATE OR REPLACE FUNCTION sys.openquery( +CREATE OR REPLACE FUNCTION sys.openquery_internal( IN linked_server text, IN query text) RETURNS SETOF RECORD AS 'babelfishpg_tsql', 'openquery_internal' LANGUAGE C VOLATILE; + +CREATE OR REPLACE FUNCTION sys.EOMONTH(date,int DEFAULT 0) +RETURNS date +AS 'babelfishpg_tsql', 'EOMONTH' +LANGUAGE C STABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.fn_listextendedproperty +( + IN "@name" sys.sysname DEFAULT NULL, + IN "@level0type" VARCHAR(128) DEFAULT NULL, + IN "@level0name" sys.sysname DEFAULT NULL, + IN "@level1type" VARCHAR(128) DEFAULT NULL, + IN "@level1name" sys.sysname DEFAULT NULL, + IN "@level2type" VARCHAR(128) DEFAULT NULL, + IN "@level2name" sys.sysname DEFAULT NULL, + OUT objtype sys.sysname, + OUT objname sys.sysname, + OUT name sys.sysname, + OUT value sys.sql_variant +) +RETURNS SETOF RECORD +AS 'babelfishpg_tsql' LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.fn_listextendedproperty TO PUBLIC; + +-- Matches and returns column length of the corresponding column of the given table +CREATE OR REPLACE FUNCTION sys.COL_LENGTH(IN object_name TEXT, IN column_name TEXT) +RETURNS SMALLINT AS $BODY$ +DECLARE + col_name TEXT; + object_id oid; + column_id INT; + column_length SMALLINT; + column_data_type TEXT; + typeid oid; + typelen INT; + typemod INT; +BEGIN + -- Get the object ID for the provided object_name + object_id := sys.OBJECT_ID(object_name, 'U'); + IF object_id IS NULL THEN + RETURN NULL; + END IF; + + -- Truncate and normalize the column name + col_name := sys.babelfish_truncate_identifier(sys.babelfish_remove_delimiter_pair(lower(column_name))); + + -- Get the column ID, typeid, length, and typmod for the provided column_name + SELECT attnum, a.atttypid, a.attlen, a.atttypmod + INTO column_id, typeid, typelen, typemod + FROM pg_attribute a + WHERE attrelid = object_id AND lower(attname) = col_name COLLATE sys.database_default; + + IF column_id IS NULL THEN + RETURN NULL; + END IF; + + -- Get the correct data type + column_data_type := sys.translate_pg_type_to_tsql(typeid); + + IF column_data_type = 'sysname' THEN + column_length := 256; + ELSIF column_data_type IS NULL THEN + + -- Check if it ia user-defined data type + SELECT sys.translate_pg_type_to_tsql(typbasetype), typlen, typtypmod + INTO column_data_type, typelen, typemod + FROM pg_type + WHERE oid = typeid; + + IF column_data_type = 'sysname' THEN + column_length := 256; + ELSE + -- Calculate column length based on base type information + column_length := sys.tsql_type_max_length_helper(column_data_type, typelen, typemod); + END IF; + ELSE + -- Calculate column length based on base type information + column_length := sys.tsql_type_max_length_helper(column_data_type, typelen, typemod); + END IF; + + RETURN column_length; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +STRICT; + +-- Matches and returns column name of the corresponding table +CREATE OR REPLACE FUNCTION sys.COL_NAME(IN table_id INT, IN column_id INT) +RETURNS sys.SYSNAME AS $$ + DECLARE + column_name TEXT; + BEGIN + SELECT attname INTO STRICT column_name + FROM pg_attribute + WHERE attrelid = table_id AND attnum = column_id AND attnum > 0; + + RETURN column_name::sys.SYSNAME; + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; + END; +$$ +LANGUAGE plpgsql IMMUTABLE +STRICT; + +-- internal helper function for date_bucket(). +CREATE OR REPLACE FUNCTION sys.date_bucket_internal_helper(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN check_date boolean, IN origin boolean, IN date ANYELEMENT default NULL) RETURNS boolean +AS +$body$ +DECLARE + date_arg_datatype regtype; +BEGIN + date_arg_datatype := pg_typeof(date); + IF datepart NOT IN ('year', 'quarter', 'month', 'week', 'doy', 'day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond') THEN + RAISE EXCEPTION '% is not a recognized date_bucket option.', datepart; + + -- Check for NULL value of number argument + ELSIF number IS NULL THEN + RAISE EXCEPTION 'Argument data type NULL is invalid for argument 2 of date_bucket function.'; + + ELSIF check_date IS NULL THEN + RAISE EXCEPTION 'Argument data type NULL is invalid for argument 3 of date_bucket function.'; + + ELSIF check_date IS false THEN + RAISE EXCEPTION 'Argument data type % is invalid for argument 3 of date_bucket function.', date_arg_datatype; + + ELSIF check_date IS true THEN + IF date_arg_datatype NOT IN ('sys.datetime'::regtype, 'sys.datetime2'::regtype, 'sys.datetimeoffset'::regtype, 'sys.smalldatetime'::regtype, 'date'::regtype, 'time'::regtype) THEN + RAISE EXCEPTION 'Argument data type % is invalid for argument 3 of date_bucket function.', date_arg_datatype; + ELSIF datepart IN ('doy', 'microsecond', 'nanosecond') THEN + RAISE EXCEPTION 'The datepart % is not supported by date function date_bucket for data type %.', datepart, date_arg_datatype; + ELSIF date_arg_datatype = 'date'::regtype AND datepart IN ('hour', 'minute', 'second', 'millisecond') THEN + RAISE EXCEPTION 'The datepart % is not supported by date function date_bucket for data type ''date''.', datepart; + ELSIF date_arg_datatype = 'time'::regtype AND datepart IN ('year', 'quarter', 'month', 'day', 'week') THEN + RAISE EXCEPTION 'The datepart % is not supported by date function date_bucket for data type ''time''.', datepart; + ELSIF origin IS false THEN + RAISE EXCEPTION 'Argument data type varchar is invalid for argument 4 of date_bucket function.'; + ELSIF number <= 0 THEN + RAISE EXCEPTION 'Invalid bucket width value passed to date_bucket function. Only positive values are allowed.'; + END IF; + RETURN true; + ELSE + RAISE EXCEPTION 'Argument data type varchar is invalid for argument 3 of date_bucket function.'; + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- Another definition of date_bucket() with arg PG_CATALOG.TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.date_bucket(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN date PG_CATALOG.TEXT, IN origin PG_CATALOG.TEXT default NULL) RETURNS PG_CATALOG.TEXT +AS +$body$ +DECLARE +BEGIN + IF date IS NULL THEN + -- check_date is NULL when date is NULL + -- check_date is false when we are sure that date can not be a valid datatype. + -- check_date is true when date might be valid datatype so check is required. + RETURN sys.date_bucket_internal_helper(datepart, number, NULL, false, 'NULL'::text); + ELSE + RETURN sys.date_bucket_internal_helper(datepart, number, false, NULL, date); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- Another definition of date_bucket() with arg date of type ANYELEMENT and origin of type TEXT. +CREATE OR REPLACE FUNCTION sys.date_bucket(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN date ANYELEMENT, IN origin PG_CATALOG.TEXT) RETURNS ANYELEMENT +AS +$body$ +DECLARE +BEGIN + IF date IS NULL THEN + RETURN sys.date_bucket_internal_helper(datepart, number, NULL, NULL, 'NULL'::text); + ELSIF pg_typeof(date) IN ('sys.datetime'::regtype, 'sys.datetime2'::regtype, 'sys.datetimeoffset'::regtype, 'sys.smalldatetime'::regtype, 'date'::regtype, 'time'::regtype) THEN + IF origin IS NULL THEN + RETURN sys.date_bucket(datepart, number, date); + ELSE + RETURN sys.date_bucket_internal_helper(datepart, number, true, false, date); + END IF; + ELSE + RETURN sys.date_bucket_internal_helper(datepart, number, false, NULL, date); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.date_bucket(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN date ANYELEMENT, IN origin ANYELEMENT default NULL) RETURNS ANYELEMENT +AS +$body$ +DECLARE + required_bucket INT; + years_diff INT; + quarters_diff INT; + months_diff INT; + hours_diff INT; + minutes_diff INT; + seconds_diff INT; + milliseconds_diff INT; + timezone INT; + result_time time; + result_date timestamp; + offset_string PG_CATALOG.text; + date_difference_interval INTERVAL; + millisec_trunc_diff_interval INTERVAL; + date_arg_datatype regtype; + is_valid boolean; +BEGIN + BEGIN + date_arg_datatype := pg_typeof(date); + is_valid := sys.date_bucket_internal_helper(datepart, number, true, true, date); + + -- If optional argument origin's value is not provided by user then set it's default value of valid datatype. + IF origin IS NULL THEN + IF date_arg_datatype = 'sys.datetime'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.datetime); + ELSIF date_arg_datatype = 'sys.datetime2'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.datetime2); + ELSIF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.datetimeoffset); + ELSIF date_arg_datatype = 'sys.smalldatetime'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.smalldatetime); + ELSIF date_arg_datatype = 'date'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS pg_catalog.date); + ELSIF date_arg_datatype = 'time'::regtype THEN + origin := CAST('00:00:00.000' AS pg_catalog.time); + END IF; + END IF; + END; + + /* support of date_bucket() for different kinds of date datatype starts here */ + -- support of date_bucket() when date is of 'time' datatype + IF date_arg_datatype = 'time'::regtype THEN + -- Find interval between date and origin and extract hour, minute, second, millisecond from the interval + date_difference_interval := date_trunc('millisecond', date) - date_trunc('millisecond', origin); + hours_diff := EXTRACT('hour' from date_difference_interval)::INT; + minutes_diff := EXTRACT('minute' from date_difference_interval)::INT; + seconds_diff := FLOOR(EXTRACT('second' from date_difference_interval))::INT; + milliseconds_diff := FLOOR(EXTRACT('millisecond' from date_difference_interval))::INT; + CASE datepart + WHEN 'hour' THEN + -- Here we are finding how many buckets we have to add in the origin so that we can reach to a bucket in which date belongs. + -- For cases where origin > date, we might end up in a bucket which exceeds date by 1 bucket. + -- For Ex. 'date_bucket(hour, 2, '01:00:00', '08:00:00')' hence check if the result_time is greater then date + -- For comparision we are trunceting the result_time to milliseconds + required_bucket := hours_diff/number; + result_time := origin + make_interval(hours => required_bucket * number); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(hours => number); + END IF; + RETURN result_time; + + WHEN 'minute' THEN + required_bucket := (hours_diff * 60 + minutes_diff)/number; + result_time := origin + make_interval(mins => required_bucket * number); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(mins => number); + END IF; + RETURN result_time; + + WHEN 'second' THEN + required_bucket := ((hours_diff * 60 + minutes_diff) * 60 + seconds_diff)/number; + result_time := origin + make_interval(secs => required_bucket * number); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(secs => number); + END IF; + RETURN result_time; + + WHEN 'millisecond' THEN + required_bucket := (((hours_diff * 60 + minutes_diff) * 60) * 1000 + milliseconds_diff)/number; + result_time := origin + make_interval(secs => ((required_bucket * number)::numeric) * 0.001); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(secs => (number::numeric) * 0.001); + END IF; + RETURN result_time; + END CASE; + + -- support of date_bucket() when date is of {'datetime2', 'datetimeoffset'} datatype + -- handling separately because both the datatypes have precision in milliseconds + ELSIF date_arg_datatype IN ('sys.datetime2'::regtype, 'sys.datetimeoffset'::regtype) THEN + -- when datepart is {year, quarter, month} make use of AGE() function to find number of buckets + IF datepart IN ('year', 'quarter', 'month') THEN + date_difference_interval := AGE(date_trunc('day', date::timestamp), date_trunc('day', origin::timestamp)); + years_diff := EXTRACT('Year' from date_difference_interval)::INT; + months_diff := EXTRACT('Month' from date_difference_interval)::INT; + CASE datepart + WHEN 'year' THEN + -- Here we are finding how many buckets we have to add in the origin so that we can reach to a bucket in which date belongs. + -- For cases where origin > date, we might end up in a bucket which exceeds date by 1 bucket. + -- For Ex. date_bucket(year, 2, '2010-01-01', '2019-01-01')) hence check if the result_time is greater then date. + -- For comparision we are trunceting the result_time to milliseconds + required_bucket := years_diff/number; + result_date := origin::timestamp + make_interval(years => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(years => number); + END IF; + + WHEN 'month' THEN + required_bucket := (12 * years_diff + months_diff)/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number); + END IF; + + WHEN 'quarter' THEN + quarters_diff := (12 * years_diff + months_diff)/3; + required_bucket := quarters_diff/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number * 3); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number*3); + END IF; + END CASE; + + -- when datepart is {week, day, hour, minute, second, millisecond} make use of built-in date_bin() postgresql function. + ELSE + -- trunceting origin to millisecond before passing it to date_bin() function. + -- store the difference between origin and trunceted origin to add it in the result of date_bin() function + date_difference_interval := concat(number, ' ', datepart)::INTERVAL; + millisec_trunc_diff_interval := (origin::timestamp - date_trunc('millisecond', origin::timestamp))::interval; + result_date = date_bin(date_difference_interval, date::timestamp, date_trunc('millisecond', origin::timestamp)) + millisec_trunc_diff_interval; + + -- Filetering cases where the required bucket ends at date then date_bin() gives start point of this bucket as result. + IF result_date + date_difference_interval <= date::timestamp THEN + result_date = result_date + date_difference_interval; + END IF; + END IF; + + -- All the above operations are performed by converting every date datatype into TIMESTAMPS. + -- datetimeoffset is typecasted into TIMESTAMPS that changes the value. + -- Ex. '2023-02-23 09:19:21.23 +10:12'::sys.datetimeoffset::timestamp => '2023-02-22 23:07:21.23' + -- The output of date_bucket() for datetimeoffset datatype will always be in the same time-zone as of provided date argument. + -- Here, converting TIMESTAMP into datetimeoffset datatype with the same timezone as of date argument. + IF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + timezone = sys.babelfish_get_datetimeoffset_tzoffset(date)::INTEGER; + offset_string = right(date::PG_CATALOG.TEXT, 6); + result_date = result_date + make_interval(mins => timezone); + RETURN concat(result_date, ' ', offset_string)::sys.datetimeoffset; + ELSE + RETURN result_date; + END IF; + + -- support of date_bucket() when date is of {'date', 'datetime', 'smalldatetime'} datatype + ELSE + -- Round datetime to fixed bins (e.g. .000, .003, .007) + IF date_arg_datatype = 'sys.datetime'::regtype THEN + date := sys.babelfish_conv_string_to_datetime('DATETIME', date::TEXT)::sys.datetime; + origin := sys.babelfish_conv_string_to_datetime('DATETIME', origin::TEXT)::sys.datetime; + END IF; + -- when datepart is {year, quarter, month} make use of AGE() function to find number of buckets + IF datepart IN ('year', 'quarter', 'month') THEN + date_difference_interval := AGE(date_trunc('day', date::timestamp), date_trunc('day', origin::timestamp)); + years_diff := EXTRACT('Year' from date_difference_interval)::INT; + months_diff := EXTRACT('Month' from date_difference_interval)::INT; + CASE datepart + WHEN 'year' THEN + -- Here we are finding how many buckets we have to add in the origin so that we can reach to a bucket in which date belongs. + -- For cases where origin > date, we might end up in a bucket which exceeds date by 1 bucket. + -- For Example. date_bucket(year, 2, '2010-01-01', '2019-01-01') hence check if the result_time is greater then date. + -- For comparision we are trunceting the result_time to milliseconds + required_bucket := years_diff/number; + result_date := origin::timestamp + make_interval(years => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(years => number); + END IF; + + WHEN 'month' THEN + required_bucket := (12 * years_diff + months_diff)/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number); + END IF; + + WHEN 'quarter' THEN + quarters_diff := (12 * years_diff + months_diff)/3; + required_bucket := quarters_diff/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number * 3); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number * 3); + END IF; + END CASE; + RETURN result_date; + + -- when datepart is {week, day, hour, minute, second, millisecond} make use of built-in date_bin() postgresql function. + ELSE + -- trunceting origin to millisecond before passing it to date_bin() function. + -- store the difference between origin and trunceted origin to add it in the result of date_bin() function + date_difference_interval := concat(number, ' ', datepart)::INTERVAL; + result_date = date_bin(date_difference_interval, date::TIMESTAMP, origin::TIMESTAMP); + -- Filetering cases where the required bucket ends at date then date_bin() gives start point of this bucket as result. + IF result_date + date_difference_interval <= date::TIMESTAMP THEN + result_date = result_date + date_difference_interval; + END IF; + RETURN result_date; + END IF; + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION SYS.TYPE_NAME(IN type_id INT) +RETURNS SYS.NVARCHAR(128) AS +'babelfishpg_tsql', 'type_name' +LANGUAGE C STABLE; + +CREATE OR REPLACE FUNCTION SYS.TYPE_ID(IN type_name SYS.NVARCHAR) +RETURNS INT AS +'babelfishpg_tsql', 'type_id' +LANGUAGE C STABLE; + +CREATE OR REPLACE FUNCTION sys.DATETRUNC(IN datepart PG_CATALOG.TEXT, IN date ANYELEMENT) RETURNS ANYELEMENT AS +$body$ +DECLARE + days_offset INT; + v_day INT; + result_date timestamp; + input_expr_timestamp timestamp; + date_arg_datatype regtype; + offset_string PG_CATALOG.TEXT; + datefirst_value INT; +BEGIN + BEGIN + /* perform input validation */ + date_arg_datatype := pg_typeof(date); + IF datepart NOT IN ('year', 'quarter', 'month', 'week', 'tsql_week', 'hour', 'minute', 'second', 'millisecond', 'microsecond', + 'doy', 'day', 'nanosecond', 'tzoffset') THEN + RAISE EXCEPTION '''%'' is not a recognized datetrunc option.', datepart; + ELSIF date_arg_datatype NOT IN ('date'::regtype, 'time'::regtype, 'sys.datetime'::regtype, 'sys.datetime2'::regtype, + 'sys.datetimeoffset'::regtype, 'sys.smalldatetime'::regtype) THEN + RAISE EXCEPTION 'Argument data type ''%'' is invalid for argument 2 of datetrunc function.', date_arg_datatype; + ELSIF datepart IN ('nanosecond', 'tzoffset') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''%''.',datepart, date_arg_datatype; + ELSIF datepart IN ('dow') THEN + RAISE EXCEPTION 'The datepart ''weekday'' is not supported by date function datetrunc for data type ''%''.', date_arg_datatype; + ELSIF date_arg_datatype = 'date'::regtype AND datepart IN ('hour', 'minute', 'second', 'millisecond', 'microsecond') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''date''.', datepart; + ELSIF date_arg_datatype = 'datetime'::regtype AND datepart IN ('microsecond') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''datetime''.', datepart; + ELSIF date_arg_datatype = 'smalldatetime'::regtype AND datepart IN ('millisecond', 'microsecond') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''smalldatetime''.', datepart; + ELSIF date_arg_datatype = 'time'::regtype THEN + IF datepart IN ('year', 'quarter', 'month', 'doy', 'day', 'week', 'tsql_week') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''time''.', datepart; + END IF; + -- Limitation in determining if the specified fractional scale (if provided any) for time datatype is + -- insufficient to support provided datepart (millisecond, microsecond) value + ELSIF date_arg_datatype IN ('datetime2'::regtype, 'datetimeoffset'::regtype) THEN + -- Limitation in determining if the specified fractional scale (if provided any) for the above datatype is + -- insufficient to support for provided datepart (millisecond, microsecond) value + END IF; + + /* input validation is complete, proceed with result calculation. */ + IF date_arg_datatype = 'time'::regtype THEN + RETURN date_trunc(datepart, date); + ELSE + input_expr_timestamp = date::timestamp; + -- preserving offset_string value in the case of datetimeoffset datatype before converting it to timestamps + IF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + offset_string = RIGHT(date::PG_CATALOG.TEXT, 6); + input_expr_timestamp := LEFT(date::PG_CATALOG.TEXT, -6)::timestamp; + END IF; + CASE + WHEN datepart IN ('year', 'quarter', 'month', 'week', 'hour', 'minute', 'second', 'millisecond', 'microsecond') THEN + result_date := date_trunc(datepart, input_expr_timestamp); + WHEN datepart IN ('doy', 'day') THEN + result_date := date_trunc('day', input_expr_timestamp); + WHEN datepart IN ('tsql_week') THEN + -- sql server datepart 'iso_week' is similar to postgres 'week' datepart + -- handle sql server datepart 'week' here based on the value of set variable 'DATEFIRST' + v_day := EXTRACT(dow from input_expr_timestamp)::INT; + datefirst_value := current_setting('babelfishpg_tsql.datefirst')::INT; + IF v_day = 0 THEN + v_day := 7; + END IF; + result_date := date_trunc('day', input_expr_timestamp); + days_offset := (7 + v_day - datefirst_value)%7; + result_date := result_date - make_interval(days => days_offset); + END CASE; + -- concat offset_string to result_date in case of datetimeoffset before converting it to datetimeoffset datatype. + IF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + RETURN concat(result_date, ' ', offset_string)::sys.datetimeoffset; + ELSE + RETURN result_date; + END IF; + END IF; + END; +END; +$body$ +LANGUAGE plpgsql STABLE; + +-- another definition of datetrunc as anyelement can not handle unknown type. +CREATE OR REPLACE FUNCTION sys.DATETRUNC(IN datepart PG_CATALOG.TEXT, IN date PG_CATALOG.TEXT) RETURNS SYS.DATETIME2 AS +$body$ +DECLARE + input_expr_datetime2 sys.datetime2; +BEGIN + IF datepart NOT IN ('year', 'quarter', 'month', 'week', 'tsql_week', 'hour', 'minute', 'second', 'millisecond', 'microsecond', + 'doy', 'day', 'nanosecond', 'tzoffset') THEN + RAISE EXCEPTION '''%'' is not a recognized datetrunc option.', datepart; + END IF; + BEGIN + input_expr_datetime2 := cast(date as sys.datetime2); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + IF input_expr_datetime2 IS NULL THEN + RETURN NULL; + ELSE + -- input string literal is valid, call the datetrunc function with datetime2 datatype. + RETURN sys.DATETRUNC(datepart, input_expr_datetime2); + END IF; +END; +$body$ +LANGUAGE plpgsql STABLE; + +CREATE OR REPLACE FUNCTION sys.bbf_pivot() +RETURNS setof record +AS 'babelfishpg_tsql', 'bbf_pivot' +LANGUAGE C STABLE; diff --git a/contrib/babelfishpg_tsql/sql/sys_procedures.sql b/contrib/babelfishpg_tsql/sql/sys_procedures.sql index 8bfe552131..306f3ed155 100644 --- a/contrib/babelfishpg_tsql/sql/sys_procedures.sql +++ b/contrib/babelfishpg_tsql/sql/sys_procedures.sql @@ -106,7 +106,8 @@ CREATE VIEW sys.babelfish_configurations_view as FROM pg_catalog.pg_settings WHERE name collate "C" like 'babelfishpg_tsql.explain_%' OR name collate "C" like 'babelfishpg_tsql.escape_hatch_%' OR - name collate "C" = 'babelfishpg_tsql.enable_pg_hint'; + name collate "C" = 'babelfishpg_tsql.enable_pg_hint' OR + name collate "C" like 'babelfishpg_tsql.isolation_level_%'; GRANT SELECT on sys.babelfish_configurations_view TO PUBLIC; CREATE OR REPLACE PROCEDURE sys.sp_babelfish_configure(IN "@option_name" varchar(128), IN "@option_value" varchar(128), IN "@option_scope" varchar(128)) @@ -202,6 +203,10 @@ CREATE OR REPLACE PROCEDURE sys.sp_droprolemember(IN "@rolename" sys.SYSNAME, IN AS 'babelfishpg_tsql', 'sp_droprolemember' LANGUAGE C; GRANT EXECUTE on PROCEDURE sys.sp_droprolemember(IN sys.SYSNAME, IN sys.SYSNAME) TO PUBLIC; +CREATE OR REPLACE PROCEDURE sys.sp_execute_postgresql(IN "@postgresStmt" sys.nvarchar) +AS 'babelfishpg_tsql', 'sp_execute_postgresql' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.sp_execute_postgresql(IN sys.nvarchar) TO PUBLIC; + CREATE OR REPLACE PROCEDURE sys.sp_addlinkedserver( IN "@server" sys.sysname, IN "@srvproduct" sys.nvarchar(128) DEFAULT NULL, IN "@provider" sys.nvarchar(128) DEFAULT 'SQLNCLI', @@ -254,6 +259,69 @@ GRANT EXECUTE ON PROCEDURE sys.sp_dropserver( IN "@server" sys.sysname, IN "@droplogins" sys.bpchar(10)) TO PUBLIC; +CREATE OR REPLACE PROCEDURE sys.sp_serveroption( IN "@server" sys.sysname, + IN "@optname" sys.varchar(35), + IN "@optvalue" sys.varchar(10)) +AS 'babelfishpg_tsql', 'sp_serveroption_internal' +LANGUAGE C; + +GRANT EXECUTE ON PROCEDURE sys.sp_serveroption( IN "@server" sys.sysname, + IN "@optname" sys.varchar(35), + IN "@optvalue" sys.varchar(10)) +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; + +CREATE OR REPLACE PROCEDURE sys.sp_testlinkedserver(IN "@servername" sys.sysname) +AS 'babelfishpg_tsql', 'sp_testlinkedserver_internal' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.sp_testlinkedserver(IN sys.sysname) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_addextendedproperty +( + "@name" sys.sysname, + "@value" sys.sql_variant = NULL, + "@level0type" VARCHAR(128) = NULL, + "@level0name" sys.sysname = NULL, + "@level1type" VARCHAR(128) = NULL, + "@level1name" sys.sysname = NULL, + "@level2type" VARCHAR(128) = NULL, + "@level2name" sys.sysname = NULL +) +AS 'babelfishpg_tsql' LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_addextendedproperty TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_updateextendedproperty +( + "@name" sys.sysname, + "@value" sys.sql_variant = NULL, + "@level0type" VARCHAR(128) = NULL, + "@level0name" sys.sysname = NULL, + "@level1type" VARCHAR(128) = NULL, + "@level1name" sys.sysname = NULL, + "@level2type" VARCHAR(128) = NULL, + "@level2name" sys.sysname = NULL +) +AS 'babelfishpg_tsql' LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_updateextendedproperty TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_dropextendedproperty +( + "@name" sys.sysname, + "@level0type" VARCHAR(128) = NULL, + "@level0name" sys.sysname = NULL, + "@level1type" VARCHAR(128) = NULL, + "@level1name" sys.sysname = NULL, + "@level2type" VARCHAR(128) = NULL, + "@level2name" sys.sysname = NULL +) +AS 'babelfishpg_tsql' LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_dropextendedproperty TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_enum_oledb_providers() +AS 'babelfishpg_tsql', 'sp_enum_oledb_providers_internal' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.sp_enum_oledb_providers() TO PUBLIC; diff --git a/contrib/babelfishpg_tsql/sql/sys_views.sql b/contrib/babelfishpg_tsql/sql/sys_views.sql index e186928ae8..d743d857d1 100644 --- a/contrib/babelfishpg_tsql/sql/sys_views.sql +++ b/contrib/babelfishpg_tsql/sql/sys_views.sql @@ -7,7 +7,6 @@ create or replace view sys.table_types_internal as SELECT pt.typrelid FROM pg_catalog.pg_type pt - INNER join sys.schemas sch on pt.typnamespace = sch.schema_id INNER JOIN pg_catalog.pg_depend dep ON pt.typrelid = dep.objid INNER JOIN pg_catalog.pg_class pc ON pc.oid = dep.objid WHERE pt.typtype = 'c' AND dep.deptype = 'i' AND pc.relkind = 'r'; @@ -62,11 +61,11 @@ select , CAST(null as integer) as history_table_id , CAST(0 as sys.bit) as is_remote_data_archive_enabled , CAST(0 as sys.bit) as is_external -from pg_class t -where t.relnamespace in (select schema_id from sys.schemas) -and t.relpersistence in ('p', 'u', 't') +from pg_class t +inner join sys.schemas sch on sch.schema_id = t.relnamespace +left join sys.table_types_internal tt on t.oid = tt.typrelid +where tt.typrelid is null and t.relkind = 'r' -and t.oid not in (select typrelid from sys.table_types_internal) and has_schema_privilege(t.relnamespace, 'USAGE') and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER'); GRANT SELECT ON sys.tables TO PUBLIC; @@ -399,12 +398,13 @@ from pg_attribute a inner join pg_class c on c.oid = a.attrelid inner join pg_type t on t.oid = a.atttypid inner join pg_namespace s on s.oid = c.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) left join pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum left join pg_collation coll on coll.oid = a.attcollation , sys.translate_pg_type_to_tsql(a.atttypid) AS tsql_type_name , sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_base_type_name where not a.attisdropped -and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and (s.nspname = 'sys' or ext.nspname is not null) -- r = ordinary table, i = index, S = sequence, t = TOAST table, v = view, m = materialized view, c = composite type, f = foreign table, p = partitioned table and c.relkind in ('r', 'v', 'm', 'f', 'p') and has_schema_privilege(s.oid, 'USAGE') @@ -1022,14 +1022,14 @@ select , 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 + , t.client_pid::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 + , t.context_info::bytea as context_info , null::bytea as sql_handle , 0 as stmt_start , 0 as stmt_end @@ -1054,30 +1054,21 @@ left join pg_catalog.pg_locks blocking_locks GRANT SELECT ON sys.sysprocesses TO PUBLIC; create or replace view sys.types As -with RECURSIVE type_code_list as -( - select distinct pg_typname as pg_type_name, tsql_typname as tsql_type_name - from sys.babelfish_typecode_list() -), -tt_internal as MATERIALIZED -( - Select * from sys.table_types_internal -) -- For System types select - ti.tsql_type_name as name + tsql_type_name as name , t.oid as system_type_id , t.oid as user_type_id , s.oid as schema_id , cast(NULL as INT) as principal_id - , sys.tsql_type_max_length_helper(ti.tsql_type_name, t.typlen, t.typtypmod, true) as max_length - , cast(sys.tsql_type_precision_helper(ti.tsql_type_name, t.typtypmod) as int) as precision - , cast(sys.tsql_type_scale_helper(ti.tsql_type_name, t.typtypmod, false) as int) as scale + , sys.tsql_type_max_length_helper(tsql_type_name, t.typlen, t.typtypmod, true) as max_length + , cast(sys.tsql_type_precision_helper(tsql_type_name, t.typtypmod) as int) as precision + , cast(sys.tsql_type_scale_helper(tsql_type_name, t.typtypmod, false) as int) as scale , CASE c.collname WHEN 'default' THEN default_collation_name ELSE c.collname END as collation_name - , case when typnotnull then 0 else 1 end as is_nullable + , case when typnotnull then cast(0 as sys.bit) else cast(1 as sys.bit) end as is_nullable , 0 as is_user_defined , 0 as is_assembly_type , 0 as default_object_id @@ -1085,11 +1076,11 @@ select , 0 as is_table_type from pg_type t inner join pg_namespace s on s.oid = t.typnamespace -inner join type_code_list ti on t.typname = ti.pg_type_name left join pg_collation c on c.oid = t.typcollation +, sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name ,cast(current_setting('babelfishpg_tsql.server_collation_name') as name) as default_collation_name where -ti.tsql_type_name IS NOT NULL +tsql_type_name IS NOT NULL and pg_type_is_visible(t.oid) and (s.nspname = 'pg_catalog' OR s.nspname = 'sys') union all @@ -1106,8 +1097,8 @@ select cast(t.typname as text) as name WHEN 'default' THEN default_collation_name ELSE c.collname END as collation_name - , case when tt.typrelid is not null then 0 - else case when typnotnull then 0 else 1 end + , case when tt.typrelid is not null then cast(0 as sys.bit) + else case when typnotnull then cast(0 as sys.bit) else cast(1 as sys.bit) end end as is_nullable -- CREATE TYPE ... FROM is implemented as CREATE DOMAIN in babel @@ -1118,14 +1109,14 @@ select cast(t.typname as text) as name , case when tt.typrelid is not null then 1 else 0 end as is_table_type from pg_type t join sys.schemas sch on t.typnamespace = sch.schema_id -left join type_code_list ti on t.typname = ti.pg_type_name left join pg_collation c on c.oid = t.typcollation -left join tt_internal tt on t.typrelid = tt.typrelid +left join sys.table_types_internal tt on t.typrelid = tt.typrelid +, sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name , sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_base_type_name , cast(current_setting('babelfishpg_tsql.server_collation_name') as name) as default_collation_name -- we want to show details of user defined datatypes created under babelfish database where - ti.tsql_type_name IS NULL + tsql_type_name IS NULL and ( -- show all user defined datatypes created under babelfish database except table types @@ -1254,6 +1245,8 @@ select t.name,t.type, ns.oid as schemaid from ('sp_addlinkedsrvlogin', 'master_dbo', 'P'), ('sp_dropserver', 'master_dbo', 'P'), ('sp_droplinkedsrvlogin', 'master_dbo', 'P'), + ('sp_testlinkedserver', 'master_dbo', 'P'), + ('sp_enum_oledb_providers','master_dbo','P'), ('fn_syspolicy_is_automation_enabled', 'msdb_dbo', 'FN'), ('syspolicy_configuration', 'msdb_dbo', 'V'), ('syspolicy_system_health_state', 'msdb_dbo', 'V') @@ -1275,108 +1268,245 @@ GRANT SELECT ON sys.shipped_objects_not_in_sys TO PUBLIC; create or replace view sys.all_objects as select - cast (name as sys.sysname) collate sys.database_default + name collate sys.database_default , cast (object_id as integer) , cast ( principal_id as integer) , cast (schema_id as integer) , cast (parent_object_id as integer) - , cast (type as char(2)) collate sys.database_default + , type collate sys.database_default , cast (type_desc as sys.nvarchar(60)) , cast (create_date as sys.datetime) , cast (modify_date as sys.datetime) - , cast (case when (schema_id::regnamespace::text = 'sys') then 1 - when name in (select name from sys.shipped_objects_not_in_sys nis - where nis.name = name and nis.schemaid = schema_id and nis.type = type) then 1 - else 0 end as sys.bit) as is_ms_shipped + , is_ms_shipped , cast (is_published as sys.bit) , cast (is_schema_published as sys.bit) from ( --- details of user defined and system tables +-- Currently for pg_class, pg_proc UNIONs, we separated user defined objects and system objects because the +-- optimiser will be able to make a better estimation of number of rows(in case the query contains a filter on +-- is_ms_shipped column) and in turn chooses a better query plan. + +-- details of system tables select - t.relname as name + t.relname::sys.sysname as name , t.oid as object_id , null::integer as principal_id , s.oid as schema_id , 0 as parent_object_id - , 'U' as type + , 'U'::char(2) as type , 'USER_TABLE' as type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , 1::sys.bit as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.table_types_internal tt on t.oid = tt.typrelid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'U' where t.relpersistence in ('p', 'u', 't') and t.relkind = 'r' -and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') -and not sys.is_table_type(t.oid) +and (s.nspname = 'sys' or (nis.name is not null and ext.nspname is not null)) +and tt.typrelid is null +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') + +union all +-- details of user defined tables +select + t.relname::sys.sysname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'U'::char(2) as type + , 'USER_TABLE' as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.table_types_internal tt on t.oid = tt.typrelid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'U' +where t.relpersistence in ('p', 'u', 't') +and t.relkind = 'r' +and s.nspname <> 'sys' and nis.name is null +and ext.nspname is not null +and tt.typrelid is null +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') + +union all +-- details of system views +select + t.relname::sys.sysname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'V'::char(2) as type + , 'VIEW'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 1::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'V' +where t.relkind = 'v' +and (s.nspname = 'sys' or (nis.name is not null and ext.nspname is not null)) and has_schema_privilege(s.oid, 'USAGE') and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') union all --- details of user defined and system views +-- Details of user defined views select - t.relname as name + t.relname::sys.sysname as name , t.oid as object_id , null::integer as principal_id , s.oid as schema_id , 0 as parent_object_id - , 'V'::varchar(2) as type + , 'V'::char(2) as type , 'VIEW'::varchar(60) as type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , 0::sys.bit as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'V' where t.relkind = 'v' -and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and s.nspname <> 'sys' and nis.name is null +and ext.nspname is not null and has_schema_privilege(s.oid, 'USAGE') -and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') union all -- details of user defined and system foreign key constraints select - c.conname as name + c.conname::sys.sysname as name , c.oid as object_id , null::integer as principal_id , s.oid as schema_id , c.conrelid as parent_object_id - , 'F' as type + , 'F'::char(2) as type , 'FOREIGN_KEY_CONSTRAINT' , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_constraint c inner join pg_namespace s on s.oid = c.connamespace -where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') -and has_schema_privilege(s.oid, 'USAGE') +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = c.conname and nis.schemaid = s.oid and nis.type = 'F' +where has_schema_privilege(s.oid, 'USAGE') and c.contype = 'f' +and (s.nspname = 'sys' or ext.nspname is not null) union all -- details of user defined and system primary key constraints select - c.conname as name + c.conname::sys.sysname as name , c.oid as object_id , null::integer as principal_id , s.oid as schema_id , c.conrelid as parent_object_id - , 'PK' as type + , 'PK'::char(2) as type , 'PRIMARY_KEY_CONSTRAINT' as type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_constraint c inner join pg_namespace s on s.oid = c.connamespace -where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') -and has_schema_privilege(s.oid, 'USAGE') +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = c.conname and nis.schemaid = s.oid and nis.type = 'PK' +where has_schema_privilege(s.oid, 'USAGE') and c.contype = 'p' +and (s.nspname = 'sys' or ext.nspname is not null) +union all +-- details of system defined procedures +select + p.proname::sys.sysname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , cast (case when tr.tgrelid is not null + then tr.tgrelid + else 0 end as int) + as parent_object_id + , case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end as type + , case p.prokind + when 'p' then 'SQL_STORED_PROCEDURE'::varchar(60) + when 'a' then 'AGGREGATE_FUNCTION'::varchar(60) + else + case + when t.typname = 'trigger' + then 'SQL_TRIGGER'::varchar(60) + when p.proretset then + case + when t.typtype = 'c' + then 'SQL_TABLE_VALUED_FUNCTION'::varchar(60) + else 'SQL_INLINE_TABLE_VALUED_FUNCTION'::varchar(60) + end + else 'SQL_SCALAR_FUNCTION'::varchar(60) + end + end as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 1::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +inner join pg_catalog.pg_type t on t.oid = p.prorettype +left join pg_trigger tr on tr.tgfoid = p.oid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = p.proname and nis.schemaid = s.oid +and nis.type = (case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end) +where (s.nspname = 'sys' or (nis.name is not null and ext.nspname is not null)) +and has_schema_privilege(s.oid, 'USAGE') +and has_function_privilege(p.oid, 'EXECUTE') + union all --- details of user defined and system defined procedures +-- details of user defined procedures select - p.proname as name + p.proname::sys.sysname as name , p.oid as object_id , null::integer as principal_id , s.oid as schema_id @@ -1385,19 +1515,19 @@ select else 0 end as int) as parent_object_id , case p.prokind - when 'p' then 'P'::varchar(2) - when 'a' then 'AF'::varchar(2) + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) else case - when pg_catalog.format_type(p.prorettype, null) = 'trigger' - then 'TR'::varchar(2) + when t.typname = 'trigger' + then 'TR'::char(2) when p.proretset then case when t.typtype = 'c' - then 'TF'::varchar(2) - else 'IF'::varchar(2) + then 'TF'::char(2) + else 'IF'::char(2) end - else 'FN'::varchar(2) + else 'FN'::char(2) end end as type , case p.prokind @@ -1405,7 +1535,7 @@ select when 'a' then 'AGGREGATE_FUNCTION'::varchar(60) else case - when pg_catalog.format_type(p.prorettype, null) = 'trigger' + when t.typname = 'trigger' then 'SQL_TRIGGER'::varchar(60) when p.proretset then case @@ -1418,20 +1548,40 @@ select end as type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , 0::sys.bit as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_proc p inner join pg_namespace s on s.oid = p.pronamespace inner join pg_catalog.pg_type t on t.oid = p.prorettype left join pg_trigger tr on tr.tgfoid = p.oid -where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = p.proname and nis.schemaid = s.oid +and nis.type = (case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end) +where s.nspname <> 'sys' and nis.name is null +and ext.nspname is not null and has_schema_privilege(s.oid, 'USAGE') and has_function_privilege(p.oid, 'EXECUTE') + union all -- details of all default constraints select - ('DF_' || o.relname || '_' || d.oid)::name as name + ('DF_' || o.relname || '_' || d.oid)::sys.sysname as name , d.oid as object_id , null::int as principal_id , o.relnamespace as schema_id @@ -1440,73 +1590,84 @@ select , 'DEFAULT_CONSTRAINT'::sys.nvarchar(60) AS type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_catalog.pg_attrdef d inner join pg_attribute a on a.attrelid = d.adrelid and d.adnum = a.attnum inner join pg_class o on d.adrelid = o.oid inner join pg_namespace s on s.oid = o.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = ('DF_' || o.relname || '_' || d.oid) and nis.schemaid = s.oid and nis.type = 'D' where a.atthasdef = 't' and a.attgenerated = '' -and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and (s.nspname = 'sys' or ext.nspname is not null) and has_schema_privilege(s.oid, 'USAGE') and has_column_privilege(a.attrelid, a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') union all -- details of all check constraints select - c.conname::name + c.conname::sys.sysname , c.oid::integer as object_id , NULL::integer as principal_id - , c.connamespace::integer as schema_id + , s.oid as schema_id , c.conrelid::integer as parent_object_id , 'C'::char(2) as type , 'CHECK_CONSTRAINT'::sys.nvarchar(60) as type_desc , null::sys.datetime as create_date , null::sys.datetime as modify_date - , 0 as is_ms_shipped + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_catalog.pg_constraint as c inner join pg_namespace s on s.oid = c.connamespace -where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') -and has_schema_privilege(s.oid, 'USAGE') +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = c.conname and nis.schemaid = s.oid and nis.type = 'C' +where has_schema_privilege(s.oid, 'USAGE') and c.contype = 'c' and c.conrelid != 0 +and (s.nspname = 'sys' or ext.nspname is not null) union all -- details of user defined and system defined sequence objects select - p.relname as name + p.relname::sys.sysname as name , p.oid as object_id , null::integer as principal_id , s.oid as schema_id , 0 as parent_object_id - , 'SO'::varchar(2) as type + , 'SO'::char(2) as type , 'SEQUENCE_OBJECT'::varchar(60) as type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 0 as is_ms_shipped + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped , 0 as is_published , 0 as is_schema_published from pg_class p inner join pg_namespace s on s.oid = p.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = p.relname and nis.schemaid = s.oid and nis.type = 'SO' where p.relkind = 'S' -and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and (s.nspname = 'sys' or ext.nspname is not null) and has_schema_privilege(s.oid, 'USAGE') union all -- details of user defined table types select - ('TT_' || tt.name || '_' || tt.type_table_object_id)::name as name + ('TT_' || tt.name || '_' || tt.type_table_object_id)::sys.sysname as name , tt.type_table_object_id as object_id , tt.principal_id as principal_id , tt.schema_id as schema_id , 0 as parent_object_id - , 'TT'::varchar(2) as type + , 'TT'::char(2) as type , 'TABLE_TYPE'::varchar(60) as type_desc , null::timestamp as create_date , null::timestamp as modify_date - , 1 as is_ms_shipped + , CAST (case when (tt.schema_id::regnamespace::text = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped , 0 as is_published , 0 as is_schema_published from sys.table_types tt +left join sys.shipped_objects_not_in_sys nis on nis.name = ('TT_' || tt.name || '_' || tt.type_table_object_id)::name and nis.schemaid = tt.schema_id and nis.type = 'TT' ) ot; GRANT SELECT ON sys.all_objects TO PUBLIC; @@ -1527,7 +1688,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 @@ -2093,7 +2257,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 @@ -2759,6 +2923,53 @@ SELECT WHERE FALSE; GRANT SELECT ON sys.spatial_index_tessellations TO PUBLIC; +CREATE OR REPLACE VIEW sys.asymmetric_keys +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('a' as sys.bpchar(2)) AS algorithm + , CAST('' as sys.nvarchar(60)) AS algorithm_desc + , CAST(0 as sys.int) AS key_length + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST(NULL as sys.varbinary(8000)) AS public_key + , CAST('' as sys.nvarchar(260)) AS attested_by + , CAST('' as sys.nvarchar(120)) AS provider_type + , CAST(NULL as sys.UNIQUEIDENTIFIER) as cryptographic_provider_guid + , CAST(NULL AS sys.sql_variant) AS cryptographic_provider_algid + +WHERE FALSE; +GRANT SELECT ON sys.asymmetric_keys TO PUBLIC; + +CREATE OR REPLACE VIEW sys.certificates +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(0 as sys.bit) AS is_active_for_begin_dialog + , CAST('' as sys.nvarchar(442)) AS issuer_name + , CAST('' as sys.nvarchar(64)) AS cert_serial_number + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST('' as sys.nvarchar(4000)) AS subject + , CAST('' as sys.datetime) AS expiry_date + , CAST('' as sys.datetime) AS start_date + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('' as sys.nvarchar(260)) as attested_by + , CAST('' as sys.datetime) AS pvt_key_last_backup_date + , CAST(0 AS sys.int) AS key_length + +WHERE FALSE; +GRANT SELECT ON sys.certificates TO PUBLIC; + CREATE OR REPLACE VIEW sys.all_parameters AS SELECT @@ -2936,8 +3147,8 @@ SELECT else NULL end, ',') from unnest(f.srvoptions) as option) as sys.sysname) AS catalog, - CAST(0 as int) AS connect_timeout, - CAST(0 as int) AS query_timeout, + CAST(s.connect_timeout as int) AS connect_timeout, + CAST(s.query_timeout as int) AS query_timeout, CAST(1 as sys.bit) AS is_linked, CAST(0 as sys.bit) AS is_remote_login_enabled, CAST(0 as sys.bit) AS is_rpc_out_enabled, @@ -2956,6 +3167,7 @@ SELECT CAST(0 as sys.bit) AS is_rda_server FROM pg_foreign_server AS f LEFT JOIN pg_foreign_data_wrapper AS w ON f.srvfdw = w.oid +LEFT JOIN sys.babelfish_server_options AS s on f.srvname = s.servername WHERE w.fdwname = 'tds_fdw'; GRANT SELECT ON sys.servers TO PUBLIC; @@ -2977,3 +3189,40 @@ LEFT JOIN pg_foreign_server AS f ON u.srvid = f.oid LEFT JOIN pg_foreign_data_wrapper AS w ON f.srvfdw = w.oid WHERE w.fdwname = 'tds_fdw'; GRANT SELECT ON sys.linked_logins TO PUBLIC; + +CREATE OR REPLACE VIEW sys.sql_expression_dependencies +AS +SELECT + CAST(0 as INT) AS referencing_id, + CAST(0 as INT) AS referencing_minor_id, + CAST(0 as sys.TINYINT) AS referencing_class, + CAST('' as NVARCHAR(60)) AS referencing_class_desc, + CAST(0 as sys.BIT) AS is_schema_bound_reference, + CAST(0 as sys.TINYINT) AS referenced_class, + CAST('' as NVARCHAR(60)) AS referenced_class_desc, + CAST('' as SYSNAME) AS referenced_server_name, + CAST('' as SYSNAME) AS referenced_database_name, + CAST('' as SYSNAME) AS referenced_schema_name, + CAST('' as SYSNAME) AS referenced_entity_name, + CAST(0 as INT) AS referenced_id, + CAST(0 as INT) AS referenced_minor_id, + CAST(0 as sys.BIT) AS is_caller_dependent, + CAST(0 as sys.BIT) AS is_ambiguous +WHERE FALSE; +GRANT SELECT ON sys.sql_expression_dependencies TO PUBLIC; + +CREATE OR REPLACE VIEW sys.database_permissions +AS +SELECT + CAST(0 as sys.tinyint) AS class, + CAST('' as sys.NVARCHAR(60)) AS class_desc, + CAST(0 as sys.int) AS major_id, + CAST(0 as sys.int) AS minor_id, + CAST(0 as sys.int) AS grantee_principal_id, + CAST(0 as sys.int) AS grantor_principal_id, + CAST('a' as sys.BPCHAR(4)) AS type, + CAST('' as sys.NVARCHAR(128)) AS permission_name, + CAST('G' as sys.BPCHAR(1)) AS state, + CAST('' as sys.NVARCHAR(60)) AS state_desc +WHERE FALSE; +GRANT SELECT ON sys.database_permissions TO PUBLIC; 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/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.0.0--2.1.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.0.0--2.1.0.sql index 64904b771f..6aea7a4447 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.0.0--2.1.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.0.0--2.1.0.sql @@ -3,6 +3,26 @@ SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- reset babelfishpg_tsql.restored_server_collation_name GUC +do +language plpgsql +$$ + declare + query text; + begin + query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); + execute query; + end; +$$; + -- Drops an object (view/function/procedure) 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. 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--2.3.0--3.0.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--3.0.0.sql index 66e14c30e3..b97faad372 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--3.0.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.3.0--3.0.0.sql @@ -4,6 +4,26 @@ -- add 'sys' to search path for the convenience SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- reset babelfishpg_tsql.restored_server_collation_name GUC +do +language plpgsql +$$ + declare + query text; + begin + query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); + execute query; + end; +$$; + -- 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. diff --git a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.4.0--3.0.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.4.0--3.0.0.sql index 66e14c30e3..b97faad372 100644 --- a/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.4.0--3.0.0.sql +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.4.0--3.0.0.sql @@ -4,6 +4,26 @@ -- add 'sys' to search path for the convenience SELECT set_config('search_path', 'sys, '||current_setting('search_path'), false); +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- reset babelfishpg_tsql.restored_server_collation_name GUC +do +language plpgsql +$$ + declare + query text; + begin + query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); + execute query; + end; +$$; + -- 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. 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..b97faad372 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.5.0--3.0.0.sql @@ -0,0 +1,167 @@ +-- 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); + +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- reset babelfishpg_tsql.restored_server_collation_name GUC +do +language plpgsql +$$ + declare + query text; + begin + query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); + execute query; + end; +$$; + +-- 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/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.6.0--3.0.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.6.0--3.0.0.sql new file mode 100644 index 0000000000..332275cfdd --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.6.0--3.0.0.sql @@ -0,0 +1,137 @@ +-- 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); + +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- reset babelfishpg_tsql.restored_server_collation_name GUC +do +language plpgsql +$$ + declare + query text; + begin + query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); + execute query; + end; +$$; + +-- 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; + +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/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.7.0--3.0.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.7.0--3.0.0.sql new file mode 100644 index 0000000000..264feeda78 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.7.0--3.0.0.sql @@ -0,0 +1,103 @@ +-- 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); + +-- please add your SQL here + +CREATE OR REPLACE FUNCTION sys.babelfish_update_server_collation_name() RETURNS VOID +LANGUAGE C +AS 'babelfishpg_common', 'babelfish_update_server_collation_name'; + +SELECT sys.babelfish_update_server_collation_name(); + +DROP FUNCTION sys.babelfish_update_server_collation_name(); + +-- reset babelfishpg_tsql.restored_server_collation_name GUC +do +language plpgsql +$$ + declare + query text; + begin + query := pg_catalog.format('alter database %s reset babelfishpg_tsql.restored_server_collation_name', CURRENT_DATABASE()); + execute query; + end; +$$; + +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; + +-- 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/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.8.0--3.0.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.8.0--3.0.0.sql new file mode 100644 index 0000000000..235479aa19 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--2.8.0--3.0.0.sql @@ -0,0 +1,83 @@ +-- 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); + +-- 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; + +-- 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/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..9bde548dda 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 @@ -964,33 +964,6 @@ CREATE OR REPLACE VIEW information_schema_tsql.SEQUENCES AS GRANT SELECT ON information_schema_tsql.SEQUENCES TO PUBLIC; -CREATE OR REPLACE VIEW information_schema_tsql.tables AS - SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", - CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", - CAST( - CASE WHEN c.reloptions[1] LIKE 'bbf_original_rel_name%' THEN substring(c.reloptions[1], 23) - ELSE c.relname END - AS sys._ci_sysname) AS "TABLE_NAME", - - CAST( - CASE WHEN c.relkind IN ('r', 'p') THEN 'BASE TABLE' - WHEN c.relkind = 'v' THEN 'VIEW' - ELSE null END - AS varchar(10)) AS "TABLE_TYPE" - - FROM sys.pg_namespace_ext nc JOIN pg_class c ON (nc.oid = c.relnamespace) - LEFT OUTER JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname - - WHERE c.relkind IN ('r', 'v', 'p') - AND (NOT pg_is_other_temp_schema(nc.oid)) - AND (pg_has_role(c.relowner, 'USAGE') - OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') - OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) - AND ext.dbid = cast(sys.db_id() as oid) - AND (NOT c.relname = 'sysdatabases'); - -GRANT SELECT ON information_schema_tsql.tables TO PUBLIC; - CREATE OR REPLACE PROCEDURE sys.sp_updatestats(IN "@resample" VARCHAR(8) DEFAULT 'NO') AS $$ BEGIN @@ -2198,7 +2171,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.1.0--3.2.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.1.0--3.2.0.sql index 9c67eac604..8fa9fb742a 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); @@ -31,12 +31,84 @@ end $$ LANGUAGE plpgsql; +CREATE TABLE sys.babelfish_server_options ( + servername sys.SYSNAME NOT NULL PRIMARY KEY COLLATE "C", + query_timeout INT +); +GRANT SELECT ON sys.babelfish_server_options TO PUBLIC; + +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_server_options', ''); + -- please add your SQL here /* * Note: These SQL statements may get executed multiple times specially when some features get backpatched. * 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, +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 @@ -55,6 +127,976 @@ SELECT FROM sys.babelfish_syslanguages; GRANT SELECT ON sys.syslanguages TO PUBLIC; +CREATE OR REPLACE VIEW sys.sp_columns_100_view AS + SELECT + CAST(t4."TABLE_CATALOG" AS sys.sysname) AS TABLE_QUALIFIER, + CAST(t4."TABLE_SCHEMA" AS sys.sysname) AS TABLE_OWNER, + CAST(t4."TABLE_NAME" AS sys.sysname) AS TABLE_NAME, + CAST(t4."COLUMN_NAME" AS sys.sysname) AS COLUMN_NAME, + CAST(t5.data_type AS smallint) AS DATA_TYPE, + CAST(coalesce(tsql_type_name, t.typname) AS sys.sysname) AS TYPE_NAME, + + CASE WHEN t4."CHARACTER_MAXIMUM_LENGTH" = -1 THEN 0::INT + WHEN a.atttypmod != -1 + THEN + CAST(coalesce(t4."NUMERIC_PRECISION", t4."CHARACTER_MAXIMUM_LENGTH", sys.tsql_type_precision_helper(t4."DATA_TYPE", a.atttypmod)) AS INT) + WHEN tsql_type_name = 'timestamp' + THEN 8 + ELSE + CAST(coalesce(t4."NUMERIC_PRECISION", t4."CHARACTER_MAXIMUM_LENGTH", sys.tsql_type_precision_helper(t4."DATA_TYPE", t.typtypmod)) AS INT) + END AS PRECISION, + + CASE WHEN a.atttypmod != -1 + THEN + CAST(sys.tsql_type_length_for_sp_columns_helper(t4."DATA_TYPE", a.attlen, a.atttypmod) AS int) + ELSE + CAST(sys.tsql_type_length_for_sp_columns_helper(t4."DATA_TYPE", a.attlen, t.typtypmod) AS int) + END AS LENGTH, + + + CASE WHEN a.atttypmod != -1 + THEN + CAST(coalesce(t4."NUMERIC_SCALE", sys.tsql_type_scale_helper(t4."DATA_TYPE", a.atttypmod, true)) AS smallint) + ELSE + CAST(coalesce(t4."NUMERIC_SCALE", sys.tsql_type_scale_helper(t4."DATA_TYPE", t.typtypmod, true)) AS smallint) + END AS SCALE, + + + CAST(coalesce(t4."NUMERIC_PRECISION_RADIX", sys.tsql_type_radix_for_sp_columns_helper(t4."DATA_TYPE")) AS smallint) AS RADIX, + case + when t4."IS_NULLABLE" = 'YES' then CAST(1 AS smallint) + else CAST(0 AS smallint) + end AS NULLABLE, + + CAST(NULL AS varchar(254)) AS remarks, + CAST(t4."COLUMN_DEFAULT" AS sys.nvarchar(4000)) AS COLUMN_DEF, + CAST(t5.sql_data_type AS smallint) AS SQL_DATA_TYPE, + CAST(t5.SQL_DATETIME_SUB AS smallint) AS SQL_DATETIME_SUB, + + CASE WHEN t4."DATA_TYPE" = 'xml' THEN 0::INT + WHEN t4."DATA_TYPE" = 'sql_variant' THEN 8000::INT + WHEN t4."CHARACTER_MAXIMUM_LENGTH" = -1 THEN 0::INT + ELSE CAST(t4."CHARACTER_OCTET_LENGTH" AS int) + END AS CHAR_OCTET_LENGTH, + + CAST(t4."ORDINAL_POSITION" AS int) AS ORDINAL_POSITION, + CAST(t4."IS_NULLABLE" AS varchar(254)) AS IS_NULLABLE, + CAST(t5.ss_data_type AS sys.tinyint) AS SS_DATA_TYPE, + CAST(0 AS smallint) AS SS_IS_SPARSE, + CAST(0 AS smallint) AS SS_IS_COLUMN_SET, + CAST(t6.is_computed as smallint) AS SS_IS_COMPUTED, + CAST(t6.is_identity as smallint) AS SS_IS_IDENTITY, + CAST(NULL AS varchar(254)) SS_UDT_CATALOG_NAME, + CAST(NULL AS varchar(254)) SS_UDT_SCHEMA_NAME, + CAST(NULL AS varchar(254)) SS_UDT_ASSEMBLY_TYPE_NAME, + CAST(NULL AS varchar(254)) SS_XML_SCHEMACOLLECTION_CATALOG_NAME, + CAST(NULL AS varchar(254)) SS_XML_SCHEMACOLLECTION_SCHEMA_NAME, + CAST(NULL AS varchar(254)) SS_XML_SCHEMACOLLECTION_NAME + + FROM pg_catalog.pg_class t1 + JOIN sys.pg_namespace_ext t2 ON t1.relnamespace = t2.oid + JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on t2.nspname = ext.nspname + JOIN information_schema_tsql.columns t4 ON (t1.relname::sys.nvarchar(128) = t4."TABLE_NAME" AND ext.orig_name = t4."TABLE_SCHEMA") + LEFT JOIN pg_attribute a on a.attrelid = t1.oid AND a.attname::sys.nvarchar(128) = t4."COLUMN_NAME" + LEFT JOIN pg_type t ON t.oid = a.atttypid + LEFT JOIN sys.columns t6 ON + ( + t1.oid = t6.object_id AND + t4."ORDINAL_POSITION" = t6.column_id + ) + , sys.translate_pg_type_to_tsql(a.atttypid) AS tsql_type_name + , sys.spt_datatype_info_table AS t5 + WHERE (t4."DATA_TYPE" = CAST(t5.TYPE_NAME AS sys.nvarchar(128)) OR (t4."DATA_TYPE" = 'bytea' AND t5.TYPE_NAME = 'image')) + AND ext.dbid = cast(sys.db_id() as oid); + +GRANT SELECT on sys.sp_columns_100_view TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.columns AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(c.relname AS sys.nvarchar(128)) AS "TABLE_NAME", + CAST(a.attname AS sys.nvarchar(128)) AS "COLUMN_NAME", + CAST(a.attnum AS int) AS "ORDINAL_POSITION", + CAST(CASE WHEN a.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) END AS sys.nvarchar(4000)) AS "COLUMN_DEFAULT", + CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END + AS varchar(3)) + AS "IS_NULLABLE", + + CAST( + CASE WHEN tsql_type_name = 'sysname' THEN sys.translate_pg_type_to_tsql(t.typbasetype) + WHEN tsql_type_name.tsql_type_name IS NULL THEN format_type(t.oid, NULL::integer) + ELSE tsql_type_name END + AS sys.nvarchar(128)) + AS "DATA_TYPE", + + CAST( + information_schema_tsql._pgtsql_char_max_length(tsql_type_name, true_typmod) + AS int) + AS "CHARACTER_MAXIMUM_LENGTH", + + CAST( + information_schema_tsql._pgtsql_char_octet_length(tsql_type_name, true_typmod) + AS int) + AS "CHARACTER_OCTET_LENGTH", + + CAST( + /* Handle Tinyint separately */ + information_schema_tsql._pgtsql_numeric_precision(tsql_type_name, true_typid, true_typmod) + AS sys.tinyint) + AS "NUMERIC_PRECISION", + + CAST( + information_schema_tsql._pgtsql_numeric_precision_radix(tsql_type_name, true_typid, true_typmod) + AS smallint) + AS "NUMERIC_PRECISION_RADIX", + + CAST( + information_schema_tsql._pgtsql_numeric_scale(tsql_type_name, true_typid, true_typmod) + AS int) + AS "NUMERIC_SCALE", + + CAST( + information_schema_tsql._pgtsql_datetime_precision(tsql_type_name, true_typmod) + AS smallint) + AS "DATETIME_PRECISION", + + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_CATALOG", + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_SCHEMA", + /* + * TODO: We need to first create mapping of collation name to char-set name; + * Until then return null. + */ + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_NAME", + + CAST(NULL as sys.nvarchar(128)) AS "COLLATION_CATALOG", + CAST(NULL as sys.nvarchar(128)) AS "COLLATION_SCHEMA", + + /* Returns Babelfish specific collation name. */ + CAST(co.collname AS sys.nvarchar(128)) AS "COLLATION_NAME", + + CAST(CASE WHEN t.typtype = 'd' AND nt.nspname <> 'pg_catalog' AND nt.nspname <> 'sys' + THEN nc.dbname ELSE null END + AS sys.nvarchar(128)) AS "DOMAIN_CATALOG", + CAST(CASE WHEN t.typtype = 'd' AND nt.nspname <> 'pg_catalog' AND nt.nspname <> 'sys' + THEN ext.orig_name ELSE null END + AS sys.nvarchar(128)) AS "DOMAIN_SCHEMA", + CAST(CASE WHEN t.typtype = 'd' AND nt.nspname <> 'pg_catalog' AND nt.nspname <> 'sys' + THEN t.typname ELSE null END + AS sys.nvarchar(128)) AS "DOMAIN_NAME" + + FROM (pg_attribute a LEFT JOIN pg_attrdef ad ON attrelid = adrelid AND attnum = adnum) + JOIN (pg_class c JOIN sys.pg_namespace_ext nc ON (c.relnamespace = nc.oid)) ON a.attrelid = c.oid + JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON a.atttypid = t.oid + LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON (bt.typnamespace = nbt.oid)) + ON (t.typtype = 'd' AND t.typbasetype = bt.oid) + LEFT JOIN pg_collation co on co.oid = a.attcollation + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname, + information_schema_tsql._pgtsql_truetypid(nt, a, t) AS true_typid, + information_schema_tsql._pgtsql_truetypmod(nt, a, t) AS true_typmod, + sys.translate_pg_type_to_tsql(true_typid) AS tsql_type_name + + WHERE (NOT pg_is_other_temp_schema(nc.oid)) + AND a.attnum > 0 AND NOT a.attisdropped + AND c.relkind IN ('r', 'v', 'p') + AND (pg_has_role(c.relowner, 'USAGE') + OR has_column_privilege(c.oid, a.attnum, + 'SELECT, INSERT, UPDATE, REFERENCES')) + AND ext.dbid = cast(sys.db_id() as oid); + +GRANT SELECT ON information_schema_tsql.columns 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 + 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 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,'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; + + 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', ''); @@ -69,6 +1111,1188 @@ 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}' +); + +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, + 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.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 '{"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; + +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 ANYELEMENT, 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; + +/* + 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; + +-- 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'); + +-- 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 is_srvrolemember('sysadmin', Base.name) = 1 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 +WHERE Base.type in ('S', 'U'); + +GRANT SELECT ON sys.syslogins TO PUBLIC; + +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; + +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)::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, + 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; + +CREATE OR REPLACE PROCEDURE sys.sp_serveroption( IN "@server" sys.sysname, + IN "@optname" sys.varchar(35), + IN "@optvalue" sys.varchar(10)) +AS 'babelfishpg_tsql', 'sp_serveroption_internal' +LANGUAGE C; + +GRANT EXECUTE ON PROCEDURE sys.sp_serveroption( IN "@server" sys.sysname, + IN "@optname" sys.varchar(35), + IN "@optvalue" sys.varchar(10)) +TO PUBLIC; + +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; + +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 + 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 = '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; + 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 + -- 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 + 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; + +CREATE OR REPLACE VIEW sys.servers +AS +SELECT + CAST(f.oid as int) AS server_id, + CAST(f.srvname as sys.sysname) AS name, + CAST('' as sys.sysname) AS product, + CAST('tds_fdw' as sys.sysname) AS provider, + CAST((select string_agg( + case + when option like 'servername=%%' then substring(option, 12) + else NULL + end, ',') + from unnest(f.srvoptions) as option) as sys.nvarchar(4000)) AS data_source, + CAST(NULL as sys.nvarchar(4000)) AS location, + CAST(NULL as sys.nvarchar(4000)) AS provider_string, + CAST((select string_agg( + case + when option like 'database=%%' then substring(option, 10) + else NULL + end, ',') + from unnest(f.srvoptions) as option) as sys.sysname) AS catalog, + CAST(0 as int) AS connect_timeout, + CAST(s.query_timeout as int) AS query_timeout, + CAST(1 as sys.bit) AS is_linked, + CAST(0 as sys.bit) AS is_remote_login_enabled, + CAST(0 as sys.bit) AS is_rpc_out_enabled, + CAST(1 as sys.bit) AS is_data_access_enabled, + CAST(0 as sys.bit) AS is_collation_compatible, + CAST(1 as sys.bit) AS uses_remote_collation, + CAST(NULL as sys.sysname) AS collation_name, + CAST(0 as sys.bit) AS lazy_schema_validation, + CAST(0 as sys.bit) AS is_system, + CAST(0 as sys.bit) AS is_publisher, + CAST(0 as sys.bit) AS is_subscriber, + CAST(0 as sys.bit) AS is_distributor, + CAST(0 as sys.bit) AS is_nonsql_subscriber, + CAST(1 as sys.bit) AS is_remote_proc_transaction_promotion_enabled, + CAST(NULL as sys.datetime) AS modify_date, + CAST(0 as sys.bit) AS is_rda_server +FROM pg_foreign_server AS f +LEFT JOIN pg_foreign_data_wrapper AS w ON f.srvfdw = w.oid +LEFT JOIN sys.babelfish_server_options AS s on f.srvname = s.servername +WHERE w.fdwname = 'tds_fdw'; +GRANT SELECT ON sys.servers TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.openquery_internal( +IN linked_server text, +IN query text) +RETURNS SETOF RECORD +AS 'babelfishpg_tsql', 'openquery_internal' +LANGUAGE C VOLATILE; + +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'); +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'openquery'); -- Drops the temporary procedure used by the upgrade script. -- Please have this be one of the last statements executed in this upgrade script. @@ -77,4 +2301,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/sql/upgrades/babelfishpg_tsql--3.2.0--3.3.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.2.0--3.3.0.sql new file mode 100644 index 0000000000..cb4a8edcad --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.2.0--3.3.0.sql @@ -0,0 +1,868 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '3.3.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; + +CREATE OR REPLACE PROCEDURE sys.sp_execute_postgresql(IN "@postgresStmt" sys.nvarchar) +AS 'babelfishpg_tsql', 'sp_execute_postgresql' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.sp_execute_postgresql(IN sys.nvarchar) TO PUBLIC; + +ALTER FUNCTION sys.parsename(VARCHAR,INT) RENAME TO parsename_deprecated_in_3_3_0; + +CREATE OR REPLACE FUNCTION sys.parsename(object_name sys.VARCHAR, object_piece int) +RETURNS sys.SYSNAME +AS 'babelfishpg_tsql', 'parsename' +LANGUAGE C IMMUTABLE STRICT; + +/** Added in 3_3_0, Deprecated in 3_4_0*/ +CREATE OR REPLACE FUNCTION sys.identity_into_int(IN typename INT, IN seed INT, IN increment INT) +RETURNS int AS 'babelfishpg_tsql' LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.identity_into_int(INT, INT, INT) TO PUBLIC; + +/** Added in 3_3_0, Deprecated in 3_4_0*/ +CREATE OR REPLACE FUNCTION sys.identity_into_smallint(IN typename INT, IN seed SMALLINT, IN increment SMALLINT) +RETURNS smallint AS 'babelfishpg_tsql' LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.identity_into_smallint(INT, SMALLINT, SMALLINT) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.identity_into_bigint(IN typename INT, IN seed BIGINT, IN increment BIGINT) +RETURNS bigint AS 'babelfishpg_tsql' LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.identity_into_bigint(INT, BIGINT, BIGINT) TO PUBLIC; + +CREATE OR REPLACE VIEW sys.sql_expression_dependencies +AS +SELECT + CAST(0 as INT) AS referencing_id, + CAST(0 as INT) AS referencing_minor_id, + CAST(0 as sys.TINYINT) AS referencing_class, + CAST('' as NVARCHAR(60)) AS referencing_class_desc, + CAST(0 as sys.BIT) AS is_schema_bound_reference, + CAST(0 as sys.TINYINT) AS referenced_class, + CAST('' as NVARCHAR(60)) AS referenced_class_desc, + CAST('' as SYSNAME) AS referenced_server_name, + CAST('' as SYSNAME) AS referenced_database_name, + CAST('' as SYSNAME) AS referenced_schema_name, + CAST('' as SYSNAME) AS referenced_entity_name, + CAST(0 as INT) AS referenced_id, + CAST(0 as INT) AS referenced_minor_id, + CAST(0 as sys.BIT) AS is_caller_dependent, + CAST(0 as sys.BIT) AS is_ambiguous +WHERE FALSE; +GRANT SELECT ON sys.sql_expression_dependencies TO PUBLIC; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'parsename_deprecated_in_3_3_0'); + +CREATE OR REPLACE PROCEDURE sys.sp_describe_first_result_set ( + "@tsql" sys.nvarchar(8000), + "@params" sys.nvarchar(8000) = NULL, + "@browse_information_mode" sys.tinyint = 0) +AS $$ +BEGIN + select * from sys.sp_describe_first_result_set_internal(@tsql, @params, @browse_information_mode) order by column_ordinal; +END; +$$ +LANGUAGE 'pltsql'; +GRANT ALL on PROCEDURE sys.sp_describe_first_result_set TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.EOMONTH(date,int DEFAULT 0) +RETURNS date +AS 'babelfishpg_tsql', 'EOMONTH' +LANGUAGE C STABLE PARALLEL SAFE; + +ALTER TABLE sys.babelfish_server_options ADD COLUMN IF NOT EXISTS connect_timeout INT; + +CREATE OR REPLACE VIEW sys.servers +AS +SELECT + CAST(f.oid as int) AS server_id, + CAST(f.srvname as sys.sysname) AS name, + CAST('' as sys.sysname) AS product, + CAST('tds_fdw' as sys.sysname) AS provider, + CAST((select string_agg( + case + when option like 'servername=%%' then substring(option, 12) + else NULL + end, ',') + from unnest(f.srvoptions) as option) as sys.nvarchar(4000)) AS data_source, + CAST(NULL as sys.nvarchar(4000)) AS location, + CAST(NULL as sys.nvarchar(4000)) AS provider_string, + CAST((select string_agg( + case + when option like 'database=%%' then substring(option, 10) + else NULL + end, ',') + from unnest(f.srvoptions) as option) as sys.sysname) AS catalog, + CAST(s.connect_timeout as int) AS connect_timeout, + CAST(s.query_timeout as int) AS query_timeout, + CAST(1 as sys.bit) AS is_linked, + CAST(0 as sys.bit) AS is_remote_login_enabled, + CAST(0 as sys.bit) AS is_rpc_out_enabled, + CAST(1 as sys.bit) AS is_data_access_enabled, + CAST(0 as sys.bit) AS is_collation_compatible, + CAST(1 as sys.bit) AS uses_remote_collation, + CAST(NULL as sys.sysname) AS collation_name, + CAST(0 as sys.bit) AS lazy_schema_validation, + CAST(0 as sys.bit) AS is_system, + CAST(0 as sys.bit) AS is_publisher, + CAST(0 as sys.bit) AS is_subscriber, + CAST(0 as sys.bit) AS is_distributor, + CAST(0 as sys.bit) AS is_nonsql_subscriber, + CAST(1 as sys.bit) AS is_remote_proc_transaction_promotion_enabled, + CAST(NULL as sys.datetime) AS modify_date, + CAST(0 as sys.bit) AS is_rda_server +FROM pg_foreign_server AS f +LEFT JOIN pg_foreign_data_wrapper AS w ON f.srvfdw = w.oid +LEFT JOIN sys.babelfish_server_options AS s on f.srvname = s.servername +WHERE w.fdwname = 'tds_fdw'; +GRANT SELECT ON sys.servers TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_testlinkedserver(IN "@servername" sys.sysname) +AS 'babelfishpg_tsql', 'sp_testlinkedserver_internal' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.sp_testlinkedserver(IN sys.sysname) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE master_dbo.sp_testlinkedserver( IN "@servername" sys.sysname) +AS 'babelfishpg_tsql', 'sp_testlinkedserver_internal' +LANGUAGE C; + +ALTER PROCEDURE master_dbo.sp_testlinkedserver OWNER TO sysadmin; + +CREATE OR REPLACE PROCEDURE sys.sp_enum_oledb_providers() +AS 'babelfishpg_tsql', 'sp_enum_oledb_providers_internal' LANGUAGE C; +GRANT EXECUTE on PROCEDURE sys.sp_enum_oledb_providers() TO PUBLIC; + +CREATE OR REPLACE PROCEDURE master_dbo.sp_enum_oledb_providers() +AS 'babelfishpg_tsql', 'sp_enum_oledb_providers_internal' +LANGUAGE C; + +ALTER PROCEDURE master_dbo.sp_enum_oledb_providers OWNER TO sysadmin; + +create or replace view sys.shipped_objects_not_in_sys AS +-- This portion of view retrieves information on objects that reside in a schema in one specfic database. +-- For example, 'master_dbo' schema can only exist in the 'master' database. +-- Internally stored schema name (nspname) must be provided. +select t.name,t.type, ns.oid as schemaid from +( + values + ('xp_qv','master_dbo','P'), + ('xp_instance_regread','master_dbo','P'), + ('sp_addlinkedserver', 'master_dbo', 'P'), + ('sp_addlinkedsrvlogin', 'master_dbo', 'P'), + ('sp_dropserver', 'master_dbo', 'P'), + ('sp_droplinkedsrvlogin', 'master_dbo', 'P'), + ('sp_testlinkedserver', 'master_dbo', 'P'), + ('sp_enum_oledb_providers','master_dbo','P'), + ('fn_syspolicy_is_automation_enabled', 'msdb_dbo', 'FN'), + ('syspolicy_configuration', 'msdb_dbo', 'V'), + ('syspolicy_system_health_state', 'msdb_dbo', 'V') +) t(name,schema_name, type) +inner join pg_catalog.pg_namespace ns on t.schema_name = ns.nspname + +union all + +-- This portion of view retrieves information on objects that reside in a schema in any number of databases. +-- For example, 'dbo' schema can exist in the 'master', 'tempdb', 'msdb', and any user created database. +select t.name,t.type, ns.oid as schemaid from +( + values + ('sysdatabases','dbo','V') +) t (name, schema_name, type) +inner join sys.babelfish_namespace_ext b on t.schema_name = b.orig_name +inner join pg_catalog.pg_namespace ns on b.nspname = ns.nspname; +GRANT SELECT ON sys.shipped_objects_not_in_sys TO PUBLIC; + +-- It is assumed that there is no data stored in the sys.extended_properties table. +ALTER TABLE sys.extended_properties RENAME TO extended_properties_deprecated_in_3_3_0; +CREATE TABLE sys.babelfish_extended_properties ( + dbid smallint NOT NULL, + schema_name name NOT NULL, + major_name name NOT NULL, + minor_name name NOT NULL, + type sys.varchar(50) NOT NULL, + name sys.sysname NOT NULL, + orig_name sys.sysname NOT NULL, + value sys.sql_variant, + PRIMARY KEY (dbid, type, schema_name, major_name, minor_name, name) +); +SELECT pg_catalog.pg_extension_config_dump('sys.babelfish_extended_properties', ''); + +CREATE OR REPLACE VIEW sys.extended_properties +AS +SELECT + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 0 + WHEN ep.type = 'SCHEMA' THEN 3 + WHEN ep.type IN ('TABLE', 'TABLE COLUMN', 'VIEW', 'SEQUENCE', 'PROCEDURE', 'FUNCTION') THEN 1 + WHEN ep.type = 'TYPE' THEN 6 + END) AS sys.tinyint) AS class, + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 'DATABASE' + WHEN ep.type = 'SCHEMA' THEN 'SCHEMA' + WHEN ep.type IN ('TABLE', 'TABLE COLUMN', 'VIEW', 'SEQUENCE', 'PROCEDURE', 'FUNCTION') THEN 'OBJECT_OR_COLUMN' + WHEN ep.type = 'TYPE' THEN 'TYPE' + END) AS sys.nvarchar(60)) AS class_desc, + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 0 + WHEN ep.type = 'SCHEMA' THEN n.oid + WHEN ep.type IN ('TABLE', 'TABLE COLUMN', 'VIEW', 'SEQUENCE') THEN c.oid + WHEN ep.type IN ('PROCEDURE', 'FUNCTION') THEN p.oid + WHEN ep.type = 'TYPE' THEN t.oid + END) AS int) AS major_id, + CAST((CASE + WHEN ep.type = 'DATABASE' THEN 0 + WHEN ep.type = 'SCHEMA' THEN 0 + WHEN ep.type IN ('TABLE', 'VIEW', 'SEQUENCE', 'PROCEDURE', 'FUNCTION', 'TYPE') THEN 0 + WHEN ep.type = 'TABLE COLUMN' THEN a.attnum + END) AS int) AS minor_id, + ep.orig_name AS name, ep.value AS value + FROM sys.babelfish_extended_properties ep + LEFT JOIN pg_catalog.pg_namespace n ON n.nspname = ep.schema_name + LEFT JOIN pg_catalog.pg_class c ON c.relname = ep.major_name AND c.relnamespace = n.oid + LEFT JOIN pg_catalog.pg_proc p ON p.proname = ep.major_name AND p.pronamespace = n.oid + LEFT JOIN pg_catalog.pg_type t ON t.typname = ep.major_name AND t.typnamespace = n.oid + LEFT JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid AND a.attname = ep.minor_name + WHERE ep.dbid = sys.db_id() AND + (CASE + WHEN ep.type = 'DATABASE' THEN true + WHEN ep.type = 'SCHEMA' THEN has_schema_privilege(n.oid, 'USAGE, CREATE') + WHEN ep.type IN ('TABLE', 'VIEW', 'SEQUENCE') THEN (has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')) + WHEN ep.type IN ('TABLE COLUMN') THEN (has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') OR has_column_privilege(a.attrelid, a.attname, 'SELECT, INSERT, UPDATE, REFERENCES')) + WHEN ep.type IN ('PROCEDURE', 'FUNCTION') THEN has_function_privilege(p.oid, 'EXECUTE') + WHEN ep.type = 'TYPE' THEN has_type_privilege(t.oid, 'USAGE') + END) + ORDER BY class, class_desc, major_id, minor_id, ep.orig_name; +GRANT SELECT ON sys.extended_properties TO PUBLIC; + +CALL sys.babelfish_drop_deprecated_object('table', 'sys', 'extended_properties_deprecated_in_3_3_0'); + +ALTER FUNCTION sys.fn_listextendedproperty RENAME TO fn_listextendedproperty_deprecated_in_3_3_0; +CREATE OR REPLACE FUNCTION sys.fn_listextendedproperty +( + IN "@name" sys.sysname DEFAULT NULL, + IN "@level0type" VARCHAR(128) DEFAULT NULL, + IN "@level0name" sys.sysname DEFAULT NULL, + IN "@level1type" VARCHAR(128) DEFAULT NULL, + IN "@level1name" sys.sysname DEFAULT NULL, + IN "@level2type" VARCHAR(128) DEFAULT NULL, + IN "@level2name" sys.sysname DEFAULT NULL, + OUT objtype sys.sysname, + OUT objname sys.sysname, + OUT name sys.sysname, + OUT value sys.sql_variant +) +RETURNS SETOF RECORD +AS 'babelfishpg_tsql' LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.fn_listextendedproperty TO PUBLIC; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'fn_listextendedproperty_deprecated_in_3_3_0'); + +CREATE OR REPLACE PROCEDURE sys.sp_addextendedproperty +( + "@name" sys.sysname, + "@value" sys.sql_variant = NULL, + "@level0type" VARCHAR(128) = NULL, + "@level0name" sys.sysname = NULL, + "@level1type" VARCHAR(128) = NULL, + "@level1name" sys.sysname = NULL, + "@level2type" VARCHAR(128) = NULL, + "@level2name" sys.sysname = NULL +) +AS 'babelfishpg_tsql' LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_addextendedproperty TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_updateextendedproperty +( + "@name" sys.sysname, + "@value" sys.sql_variant = NULL, + "@level0type" VARCHAR(128) = NULL, + "@level0name" sys.sysname = NULL, + "@level1type" VARCHAR(128) = NULL, + "@level1name" sys.sysname = NULL, + "@level2type" VARCHAR(128) = NULL, + "@level2name" sys.sysname = NULL +) +AS 'babelfishpg_tsql' LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_updateextendedproperty TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.sp_dropextendedproperty +( + "@name" sys.sysname, + "@level0type" VARCHAR(128) = NULL, + "@level0name" sys.sysname = NULL, + "@level1type" VARCHAR(128) = NULL, + "@level1name" sys.sysname = NULL, + "@level2type" VARCHAR(128) = NULL, + "@level2name" sys.sysname = NULL +) +AS 'babelfishpg_tsql' LANGUAGE C; +GRANT EXECUTE ON PROCEDURE sys.sp_dropextendedproperty 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 + , t.client_pid::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; + +CREATE OR REPLACE FUNCTION sys.host_id() +RETURNS sys.VARCHAR(10) AS 'babelfishpg_tsql' LANGUAGE C IMMUTABLE PARALLEL SAFE; +GRANT EXECUTE ON FUNCTION sys.host_id() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sysdatetime() RETURNS datetime2 + AS $$select statement_timestamp()::datetime2;$$ + LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION sys.sysdatetime() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sysdatetimeoffset() RETURNS sys.datetimeoffset + -- Casting to text as there are not type cast function from timestamptz to datetimeoffset + AS $$select cast(cast(statement_timestamp() as text) as sys.datetimeoffset);$$ + LANGUAGE SQL STABLE; +GRANT EXECUTE ON FUNCTION sys.sysdatetimeoffset() TO PUBLIC; + + +CREATE OR REPLACE FUNCTION sys.sysutcdatetime() RETURNS sys.datetime2 + AS $$select (statement_timestamp() AT TIME ZONE 'UTC'::pg_catalog.text)::sys.datetime2;$$ + LANGUAGE SQL STABLE; +GRANT EXECUTE ON FUNCTION sys.sysutcdatetime() TO PUBLIC; + + +CREATE OR REPLACE FUNCTION sys.getdate() RETURNS sys.datetime + AS $$select date_trunc('millisecond', statement_timestamp()::pg_catalog.timestamp)::sys.datetime;$$ + LANGUAGE SQL STABLE; +GRANT EXECUTE ON FUNCTION sys.getdate() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.getutcdate() RETURNS sys.datetime + AS $$select date_trunc('millisecond', statement_timestamp() AT TIME ZONE 'UTC'::pg_catalog.text)::sys.datetime;$$ + LANGUAGE SQL STABLE; +GRANT EXECUTE ON FUNCTION sys.getutcdate() TO PUBLIC; + +-- sp_babelfish_autoformat is a helper procedure which formats the contents of a table (or view) +-- as narrowly as possible given its actual column contents. +-- This proc is currently only used by sp_who but could be applied more generically. +-- A complication is that the metadata for #tmp tables cannot be found in the babelfish +-- catalogs, so we have to use some trickery to make things work. +-- Not all datatypes are handled as well as might be possible, but it is sufficient for +-- the current purposes. +-- Note that this proc may increase the response time for the first execution of sp_who, but +-- we are looking at prioritizing user-friendliness (easy-to-read output) here. Also, sp_who +-- is very unlikely to be part of performance-critical workload. +CREATE OR REPLACE PROCEDURE sys.sp_babelfish_autoformat( + IN "@tab" sys.VARCHAR(257) DEFAULT NULL, + IN "@orderby" sys.VARCHAR(1000) DEFAULT '', + IN "@printrc" sys.bit DEFAULT 1, + IN "@hiddencols" sys.VARCHAR(1000) DEFAULT NULL) +LANGUAGE 'pltsql' +AS $$ +BEGIN + SET NOCOUNT ON + DECLARE @rc INT + DECLARE @id INT + DECLARE @objtype sys.VARCHAR(2) + DECLARE @msg sys.VARCHAR(200) + + IF @tab IS NULL + BEGIN + RAISERROR('Must specify table name', 16, 1) + RETURN + END + + IF TRIM(@tab) = '' + BEGIN + RAISERROR('Must specify table name', 16, 1) + RETURN + END + + -- Since we cannot find #tmp tables in the Babelfish catalogs, we cannot check + -- their existence other than by trying to select from them + -- Function sys.babelfish_get_enr_list() could be used to determine if a #tmp table + -- exists but the columns and datatypes can still not be retrieved, it would be of + -- little use here. + -- NB: not handling uncommon but valid T-SQL syntax '.#tmp' for #tmp tables + IF sys.SUBSTRING(@tab,1,1) <> '#' + BEGIN + SET @id = sys.OBJECT_ID(@tab) + IF @id IS NULL + BEGIN + IF sys.SUBSTRING(UPPER(@tab),1,4) = 'DBO.' + BEGIN + SET @id = sys.OBJECT_ID('SYS.' + sys.SUBSTRING(@tab,5)) + END + IF @id IS NULL + BEGIN + SET @msg = 'Table or view '''+@tab+''' not found' + RAISERROR(@msg, 16, 1) + RETURN + END + END + END + + SELECT @objtype = type COLLATE DATABASE_DEFAULT FROM sys.sysobjects WHERE id = @id + IF @objtype NOT IN ('U', 'S', 'V') + BEGIN + SET @msg = ''''+@tab+''' is not a table or view' + RAISERROR(@msg, 16, 1) + RETURN + END + + -- check for 'ORDER BY', if specified + SET @orderby = TRIM(@orderby) + IF @orderby <> '' + BEGIN + IF UPPER(@orderby) NOT LIKE 'ORDER BY%' + BEGIN + RAISERROR('@orderby parameter must start with ''ORDER BY''', 16, 1) + RETURN + END + END + + -- columns to hide in final client output + -- assuming delimited column names do not contain spaces or commas inside the name + -- remove any spaces around the commas: + WHILE (sys.CHARINDEX(' ,', @hiddencols) > 0) or (sys.CHARINDEX(', ', @hiddencols) > 0) + BEGIN + SET @hiddencols = sys.REPLACE(@hiddencols, ' ,', ',') + SET @hiddencols = sys.REPLACE(@hiddencols, ', ', ',') + END + IF sys.LEN(@hiddencols) IS NOT NULL SET @hiddencols = ',' + @hiddencols + ',' + SET @hiddencols = UPPER(@hiddencols) + + -- Need to use a guaranteed-uniquely named table as intermediate step since we cannot + -- access the metadata in case a #tmp table is passed as argument + -- But when we copy the #tmp table into another table, we get all the attributes and metadata + DECLARE @tmptab sys.VARCHAR(63) = 'sp_babelfish_autoformat' + sys.REPLACE(NEWID(), '-', '') + DECLARE @tmptab2 sys.VARCHAR(63) = 'sp_babelfish_autoformat' + sys.REPLACE(NEWID(), '-', '') + DECLARE @cmd sys.VARCHAR(1000) = 'SELECT * INTO ' + @tmptab + ' FROM ' + @tab + + BEGIN TRY + -- create the first work table + EXECUTE(@cmd) + + -- Get the columns + SELECT + c.name AS colname, c.colid AS colid, t.name AS basetype, 0 AS maxlen + INTO #sp_bbf_autoformat + FROM sys.syscolumns c left join sys.systypes t + ON c.xusertype = t.xusertype + WHERE c.id = sys.OBJECT_ID(@tmptab) + ORDER BY c.colid + + -- Get max length for each column based on the data + DECLARE @colname sys.VARCHAR(63), @basetype sys.VARCHAR(63), @maxlen int + DECLARE c CURSOR FOR SELECT colname, basetype, maxlen FROM #sp_bbf_autoformat ORDER BY colid + OPEN c + WHILE 1=1 + BEGIN + FETCH c INTO @colname, @basetype, @maxlen + IF @@fetch_status <> 0 BREAK + SET @cmd = 'DECLARE @i INT SELECT @i=ISNULL(MAX(sys.LEN(CAST([' + @colname + '] AS sys.VARCHAR(500)))),4) FROM ' + @tmptab + ' UPDATE #sp_bbf_autoformat SET maxlen = @i WHERE colname = ''' + @colname + '''' + EXECUTE(@cmd) + END + CLOSE c + DEALLOCATE c + + -- Generate the final SELECT + DECLARE @selectlist sys.VARCHAR(8000) = '' + DECLARE @collist sys.VARCHAR(8000) = '' + DECLARE @fmtstart sys.VARCHAR(30) = '' + DECLARE @fmtend sys.VARCHAR(30) = '' + OPEN c + WHILE 1=1 + BEGIN + FETCH c INTO @colname, @basetype, @maxlen + IF @@fetch_status <> 0 BREAK + IF sys.LEN(@colname) > @maxlen SET @maxlen = sys.LEN(@colname) + IF @maxlen <= 0 SET @maxlen = 1 + + IF (sys.CHARINDEX(',' + UPPER(@colname) + ',', @hiddencols) > 0) OR (sys.CHARINDEX(',[' + UPPER(@colname) + '],', @hiddencols) > 0) + BEGIN + SET @selectlist += ' [' + @colname + '],' + END + ELSE + BEGIN + SET @fmtstart = '' + SET @fmtend = '' + IF @basetype IN ('tinyint', 'smallint', 'int', 'bigint', 'decimal', 'numeric', 'real', 'float') + BEGIN + SET @fmtstart = 'CAST(right(space('+CAST(@maxlen AS sys.VARCHAR)+')+' + SET @fmtend = ','+CAST(@maxlen AS sys.VARCHAR)+') AS sys.VARCHAR(' + CAST(@maxlen AS sys.VARCHAR) + '))' + END + + SET @selectlist += ' '+@fmtstart+'CAST([' + @colname + '] AS sys.VARCHAR(' + CAST(@maxlen AS sys.VARCHAR) + '))'+@fmtend+' AS [' + @colname + '],' + SET @collist += '['+@colname + '],' + END + END + CLOSE c + DEALLOCATE c + + -- Remove redundant commas + SET @collist = sys.SUBSTRING(@collist, 1, sys.LEN(@collist)-1) + SET @selectlist = sys.SUBSTRING(@selectlist, 1, sys.LEN(@selectlist)-1) + SET @selectlist = 'SELECT ' + @selectlist + ' INTO ' + @tmptab2 + ' FROM ' + @tmptab + ' ' + @orderby + + -- create the second work table + EXECUTE(@selectlist) + + -- perform the final SELECT to generate the result set for the client + EXECUTE('SELECT ' + @collist + ' FROM ' + @tmptab2) + + -- PRINT rowcount if desired + SET @rc = @@rowcount + IF @printrc = 1 + BEGIN + PRINT ' ' + SET @cmd = '(' + CAST(@rc AS sys.VARCHAR) + ' rows affected)' + PRINT @cmd + END + + -- Cleanup: these work tables are permanent tables after all + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab) + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab2) + END TRY + BEGIN CATCH + -- Cleanup in case of an unexpected error + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab) + EXECUTE('DROP TABLE IF EXISTS ' + @tmptab2) + END CATCH + + RETURN +END +$$; +GRANT EXECUTE ON PROCEDURE sys.sp_babelfish_autoformat(IN sys.VARCHAR(257), IN sys.VARCHAR(1000), sys.bit, sys.VARCHAR(1000)) TO PUBLIC; + + +-- sp_who presents the contents of sysprocesses in a human-readable format. +-- With 'postgres' as argument or with optional second argument as 'postgres', +-- active PG connections will also be reported; by default only TDS connections are reported. +CREATE OR REPLACE PROCEDURE sys.sp_who( + IN "@loginame" sys.sysname DEFAULT NULL, + IN "@option" sys.VARCHAR(30) DEFAULT NULL) +LANGUAGE 'pltsql' +AS $$ +BEGIN + SET NOCOUNT ON + DECLARE @msg sys.VARCHAR(200) + DECLARE @show_pg BIT = 0 + DECLARE @hide_col sys.VARCHAR(50) + + IF @option IS NOT NULL + BEGIN + IF LOWER(TRIM(@option)) <> 'postgres' + BEGIN + RAISERROR('Parameter @option can only be ''postgres''', 16, 1) + RETURN + END + END + + -- Take a copy of sysprocesses so that we reference it only once + SELECT DISTINCT * INTO #sp_who_sysprocesses FROM sys.sysprocesses + + -- Get the executing statement for each spid and extract the main stmt type + -- This is for informational purposes only + SELECT pid, query INTO #sp_who_tmp FROM pg_stat_activity pgsa + + UPDATE #sp_who_tmp SET query = ' ' + TRIM(UPPER(query)) + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, chr(9), ' ') + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, chr(10), ' ') + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, chr(13), ' ') + WHILE (SELECT count(*) FROM #sp_who_tmp WHERE sys.CHARINDEX(' ',query)>0) > 0 + BEGIN + UPDATE #sp_who_tmp SET query = sys.REPLACE(query, ' ', ' ') + END + + -- Determine type of stmt to report by sp_who: very basic only + -- NB: not handling presence of comments in the query string + UPDATE #sp_who_tmp + SET query = + CASE + WHEN PATINDEX('%[^a-zA-Z0-9_]UPDATE[^a-zA-Z0-9_]%', query) > 0 THEN 'UPDATE' + WHEN PATINDEX('%[^a-zA-Z0-9_]DELETE[^a-zA-Z0-9_]%', query) > 0 THEN 'DELETE' + WHEN PATINDEX('%[^a-zA-Z0-9_]INSERT[^a-zA-Z0-9_]%', query) > 0 THEN 'INSERT' + WHEN PATINDEX('%[^a-zA-Z0-9_]SELECT[^a-zA-Z0-9_]%', query) > 0 THEN 'SELECT' + WHEN PATINDEX('%[^a-zA-Z0-9_]WAITFOR[^a-zA-Z0-9_]%', query) > 0 THEN 'WAITFOR' + WHEN PATINDEX('%[^a-zA-Z0-9_]CREATE ]%', query) > 0 THEN sys.SUBSTRING(query,1,sys.CHARINDEX('CREATE ', query)) + WHEN PATINDEX('%[^a-zA-Z0-9_]ALTER ]%', query) > 0 THEN sys.SUBSTRING(query,1,sys.CHARINDEX('ALTER ', query)) + WHEN PATINDEX('%[^a-zA-Z0-9_]DROP ]%', query) > 0 THEN sys.SUBSTRING(query,1,sys.CHARINDEX('DROP ', query)) + ELSE sys.SUBSTRING(query, 1, sys.CHARINDEX(' ', query)) + END + + UPDATE #sp_who_tmp + SET query = sys.SUBSTRING(query,1, 8-1 + sys.CHARINDEX(' ', sys.SUBSTRING(query,8,99))) + WHERE query LIKE 'CREATE %' OR query LIKE 'ALTER %' OR query LIKE 'DROP %' + + -- The executing spid is always shown as doing a SELECT + UPDATE #sp_who_tmp SET query = 'SELECT' WHERE pid = @@spid + UPDATE #sp_who_tmp SET query = TRIM(query) + + -- Get all current connections + SELECT + spid, + MAX(blocked) AS blocked, + 0 AS ecid, + CAST('' AS sys.VARCHAR(100)) AS status, + CAST('' AS sys.VARCHAR(100)) AS loginname, + CAST('' AS sys.VARCHAR(100)) AS hostname, + 0 AS dbid, + CAST('' AS sys.VARCHAR(100)) AS cmd, + 0 AS request_id, + CAST('TDS' AS sys.VARCHAR(20)) AS connection, + hostprocess + INTO #sp_who_proc + FROM #sp_who_sysprocesses + GROUP BY spid, status, hostprocess + + -- Add attributes to each connection + UPDATE #sp_who_proc + SET ecid = sp.ecid, + status = sp.status, + loginname = sp.loginname, + hostname = sp.hostname, + dbid = sp.dbid, + request_id = sp.request_id + FROM #sp_who_sysprocesses sp + WHERE #sp_who_proc.spid = sp.spid + + -- Identify PG connections: the hostprocess PID comes from the TDS login packet + -- and therefore PG connections do not have a value here + UPDATE #sp_who_proc + SET connection = 'PostgreSQL' + WHERE hostprocess IS NULL + + -- Keep or delete PG connections + IF (LOWER(@loginame) = 'postgres' OR LOWER(@option) = 'postgres') + begin + -- Show PG connections; these have dbid = 0 + -- This is a Babelfish-specific enhancement, since PG connections may also be active in the Babelfish DB + -- and it may be useful to see these displayed + SET @show_pg = 1 + + -- blank out the loginame parameter for the tests below + IF LOWER(@loginame) = 'postgres' SET @loginame = NULL + END + + -- By default, do not show the column indicating the connection type since SQL Server does not have this column + SET @hide_col = 'connection' + + IF (@show_pg = 1) + BEGIN + SET @hide_col = '' + END + ELSE + BEGIN + -- Delete PG connections + DELETE #sp_who_proc + WHERE dbid = 0 + END + + -- Apply filter if specified + IF (@loginame IS NOT NULL) + BEGIN + IF (TRIM(@loginame) = '') + BEGIN + -- Raise error + SET @msg = ''''+@loginame+''' is not a valid login or you do not have permission.' + RAISERROR(@msg, 16, 1) + RETURN + END + + IF (sys.ISNUMERIC(@loginame) = 1) + BEGIN + -- Remove all connections except the specified one + DELETE #sp_who_proc + WHERE spid <> CAST(@loginame AS INT) + END + ELSE + BEGIN + IF (LOWER(@loginame) = 'active') + BEGIN + -- Remove all 'idle' connections + DELETE #sp_who_proc + WHERE status = 'idle' + END + ELSE + BEGIN + -- Verify the specified login name exists + IF (sys.SUSER_ID(@loginame) IS NULL) + BEGIN + SET @msg = ''''+@loginame+''' is not a valid login or you do not have permission.' + RAISERROR(@msg, 16, 1) + RETURN + END + ELSE + BEGIN + -- Keep only connections for the specified login + DELETE #sp_who_proc + WHERE sys.SUSER_ID(loginname) <> sys.SUSER_ID(@loginame) + END + END + END + END + + -- Create final result set; use DISTINCT since there are usually duplicate rows from the PG catalogs + SELECT distinct + p.spid AS spid, + p.ecid AS ecid, + CAST(LEFT(p.status,20) AS sys.VARCHAR(20)) AS status, + CAST(LEFT(p.loginname,40) AS sys.VARCHAR(40)) AS loginame, + CAST(LEFT(p.hostname,60) AS sys.VARCHAR(60)) AS hostname, + p.blocked AS blk, + CAST(LEFT(db_name(p.dbid),40) AS sys.VARCHAR(40)) AS dbname, + CAST(LEFT(#sp_who_tmp.query,30)as sys.VARCHAR(30)) AS cmd, + p.request_id AS request_id, + connection + INTO #sp_who_tmp2 + FROM #sp_who_proc p, #sp_who_tmp + WHERE p.spid = #sp_who_tmp.pid + ORDER BY spid + + -- Patch up remaining cases + UPDATE #sp_who_tmp2 + SET cmd = 'AWAITING COMMAND' + WHERE TRIM(ISNULL(cmd,'')) = '' AND status = 'idle' + + UPDATE #sp_who_tmp2 + SET cmd = 'UNKNOWN' + WHERE TRIM(cmd) = '' + + -- Format the result set as narrow as possible for readability + SET @hide_col += ',hostprocess' + EXECUTE sys.sp_babelfish_autoformat @tab='#sp_who_tmp2', @orderby='ORDER BY spid', @hiddencols=@hide_col, @printrc=0 + RETURN +END +$$; +GRANT EXECUTE ON PROCEDURE sys.sp_who(IN sys.sysname, IN sys.VARCHAR(30)) TO PUBLIC; + +-- 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); + +CREATE OR REPLACE FUNCTION objectproperty( + id INT, + property SYS.VARCHAR + ) +RETURNS INT AS +'babelfishpg_tsql', 'objectproperty_internal' +LANGUAGE C STABLE; + +CREATE OR REPLACE FUNCTION sys.SMALLDATETIMEFROMPARTS(IN p_year INTEGER, + IN p_month INTEGER, + IN p_day INTEGER, + IN p_hour INTEGER, + IN p_minute INTEGER + ) +RETURNS sys.smalldatetime +AS +$BODY$ +DECLARE + v_ressmalldatetime TIMESTAMP WITHOUT TIME ZONE; + v_string pg_catalog.text; + p_seconds INTEGER; +BEGIN + IF p_year IS NULL OR p_month is NULL OR p_day IS NULL OR p_hour IS NULL OR p_minute IS NULL THEN + RETURN NULL; + END IF; + + -- Check if arguments are out of range + IF ((p_year NOT BETWEEN 1900 AND 2079) OR + (p_month NOT BETWEEN 1 AND 12) OR + (p_day NOT BETWEEN 1 AND 31) OR + (p_hour NOT BETWEEN 0 AND 23) OR + (p_minute NOT BETWEEN 0 AND 59) OR (p_year = 2079 AND p_month > 6) OR (p_year = 2079 AND p_month = 6 AND p_day > 6)) + THEN + RAISE invalid_datetime_format; + END IF; + p_seconds := 0; + v_ressmalldatetime := make_timestamp(p_year, + p_month, + p_day, + p_hour, + p_minute, + p_seconds); + + v_string := v_ressmalldatetime::pg_catalog.text; + RETURN CAST(v_string AS sys.SMALLDATETIME); +EXCEPTION + WHEN invalid_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type smalldatetime, 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.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +ALTER FUNCTION sys.replace (in input_string text, in pattern text, in replacement text) IMMUTABLE; + +-- 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/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql new file mode 100644 index 0000000000..fe14153457 --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.3.0--3.4.0.sql @@ -0,0 +1,4512 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '3.4.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; + +-- Please add your SQLs here +/* + * Note: These SQL statements may get executed multiple times specially when some features get backpatched. + * So make sure that any SQL statement (DDL/DML) being added here can be executed multiple times without affecting + * final behaviour. + */ + + + +CREATE OR REPLACE VIEW sys.asymmetric_keys +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('a' as sys.bpchar(2)) AS algorithm + , CAST('' as sys.nvarchar(60)) AS algorithm_desc + , CAST(0 as sys.int) AS key_length + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST(NULL as sys.varbinary(8000)) AS public_key + , CAST('' as sys.nvarchar(260)) AS attested_by + , CAST('' as sys.nvarchar(120)) AS provider_type + , CAST(NULL as sys.UNIQUEIDENTIFIER) as cryptographic_provider_guid + , CAST(NULL AS sys.sql_variant) AS cryptographic_provider_algid + +WHERE FALSE; +GRANT SELECT ON sys.asymmetric_keys TO PUBLIC; + +CREATE OR REPLACE VIEW sys.certificates +AS +SELECT + CAST('' as sys.sysname) AS name + , CAST(0 as sys.int) AS principal_id + , CAST(0 as sys.int) AS asymmetric_key_id + , CAST('a' as sys.bpchar(2)) AS pvt_key_encryption_type + , CAST('' as sys.nvarchar(60)) AS pvt_key_encryption_type_desc + , CAST(0 as sys.bit) AS is_active_for_begin_dialog + , CAST('' as sys.nvarchar(442)) AS issuer_name + , CAST('' as sys.nvarchar(64)) AS cert_serial_number + , CAST(null as sys.varbinary(85)) as sid + , CAST('' as sys.nvarchar(128)) AS string_sid + , CAST('' as sys.nvarchar(4000)) AS subject + , CAST('' as sys.datetime) AS expiry_date + , CAST('' as sys.datetime) AS start_date + , CAST(null as sys.varbinary(32)) as thumbprint + , CAST('' as sys.nvarchar(260)) as attested_by + , CAST('' as sys.datetime) AS pvt_key_last_backup_date + , CAST(0 AS sys.int) AS key_length + +WHERE FALSE; +GRANT SELECT ON sys.certificates TO PUBLIC; + +CREATE OR REPLACE VIEW sys.database_permissions +AS +SELECT + CAST(0 as sys.tinyint) AS class, + CAST('' as sys.NVARCHAR(60)) AS class_desc, + CAST(0 as sys.int) AS major_id, + CAST(0 as sys.int) AS minor_id, + CAST(0 as sys.int) AS grantee_principal_id, + CAST(0 as sys.int) AS grantor_principal_id, + CAST('a' as sys.bpchar(4)) AS type, + CAST('' as sys.NVARCHAR(128)) AS permission_name, + CAST('G' as sys.bpchar(1)) AS state, + CAST('' as sys.NVARCHAR(60)) AS state_desc +WHERE FALSE; +GRANT SELECT ON sys.database_permissions TO PUBLIC; + + +CREATE OR REPLACE VIEW information_schema_tsql.key_column_usage AS + SELECT + CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA", + CAST(c.conname AS sys.nvarchar(128)) AS "CONSTRAINT_NAME", + CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(r.relname AS sys.nvarchar(128)) AS "TABLE_NAME", + CAST(a.attname AS sys.nvarchar(128)) AS "COLUMN_NAME", + CAST(ord AS int) AS "ORDINAL_POSITION" + FROM + pg_constraint c + JOIN pg_class r ON r.oid = c.conrelid AND c.contype in ('p','u','f') AND r.relkind in ('r','p') + JOIN sys.pg_namespace_ext nc ON nc.oid = c.connamespace AND r.relnamespace = nc.oid + JOIN sys.babelfish_namespace_ext ext ON ext.nspname = nc.nspname AND ext.dbid = sys.db_id() + CROSS JOIN unnest(c.conkey) WITH ORDINALITY AS ak(j,ord) + LEFT JOIN pg_attribute a ON a.attrelid = r.oid AND a.attnum = ak.j + WHERE + pg_has_role(r.relowner, 'USAGE'::text) + OR has_column_privilege(r.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + AND NOT pg_is_other_temp_schema(nc.oid) + ; +GRANT SELECT ON information_schema_tsql.key_column_usage TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.typeproperty( + typename sys.VARCHAR, + property sys.VARCHAR + ) +RETURNS INT +AS $$ +DECLARE +BEGIN + RETURN NULL; +END; +$$ +LANGUAGE plpgsql STABLE; + +CREATE OR REPLACE FUNCTION sys.DATETIMEOFFSETFROMPARTS(IN p_year INTEGER, + IN p_month INTEGER, + IN p_day INTEGER, + IN p_hour INTEGER, + IN p_minute INTEGER, + IN p_seconds INTEGER, + IN p_fractions INTEGER, + IN p_hour_offset INTEGER, + IN p_minute_offset INTEGER, + IN p_precision NUMERIC) +RETURNS sys.DATETIMEOFFSET +AS +$BODY$ +DECLARE + v_err_message SYS.VARCHAR; + v_fractions SYS.VARCHAR; + v_precision SMALLINT; + v_calc_seconds NUMERIC; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + v_string pg_catalog.text; + v_sign pg_catalog.text; +BEGIN + v_fractions := p_fractions::SYS.VARCHAR; + IF p_precision IS NULL THEN + RAISE EXCEPTION 'Scale argument is not valid. Valid expressions for data type datetimeoffset scale argument are integer constants and integer constant expressions.'; + END IF; + IF p_year IS NULL OR p_month is NULL OR p_day IS NULL OR p_hour IS NULL OR p_minute IS NULL OR p_seconds IS NULL OR p_fractions IS NULL + OR p_hour_offset IS NULL OR p_minute_offset is NULL THEN + RETURN NULL; + END IF; + v_precision := p_precision::SMALLINT; + + IF (scale(p_precision) > 0) THEN + RAISE most_specific_type_mismatch; + + -- Check if arguments are out of range + ELSIF ((p_year NOT BETWEEN 0001 AND 9999) OR + (p_month NOT BETWEEN 1 AND 12) OR + (p_day NOT BETWEEN 1 AND 31) OR + (p_hour NOT BETWEEN 0 AND 23) OR + (p_minute NOT BETWEEN 0 AND 59) OR + (p_seconds NOT BETWEEN 0 AND 59) OR + (p_hour_offset NOT BETWEEN -14 AND 14) OR + (p_minute_offset NOT BETWEEN -59 AND 59) OR + (p_hour_offset * p_minute_offset < 0) OR + (p_hour_offset = 14 AND p_minute_offset != 0) OR + (p_hour_offset = -14 AND p_minute_offset != 0) OR + (p_fractions != 0 AND char_length(v_fractions) > p_precision::SMALLINT)) + 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 := format('%s.%s', + p_seconds, + substring(rpad(lpad(v_fractions, v_precision, '0'), 7, '0'), 1, 6))::NUMERIC; + + v_resdatetime := make_timestamp(p_year, + p_month, + p_day, + p_hour, + p_minute, + v_calc_seconds); + v_sign := ( + SELECT CASE + WHEN (p_hour_offset) > 0 + THEN '+' + WHEN (p_hour_offset) = 0 AND (p_minute_offset) >= 0 + THEN '+' + ELSE '-' + END + ); + v_string := CONCAT(v_resdatetime::pg_catalog.text,v_sign,abs(p_hour_offset)::SMALLINT::text,':', + abs(p_minute_offset)::SMALLINT::text); + BEGIN + RETURN cast(v_string AS sys.datetimeoffset); + exception + WHEN others THEN + RAISE invalid_datetime_format; + END; +EXCEPTION + WHEN most_specific_type_mismatch THEN + RAISE USING MESSAGE := 'Scale argument is not valid. Valid expressions for data type datetimeoffset 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_datetime_format THEN + RAISE USING MESSAGE := 'Cannot construct data type datetimeoffset, 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 + RAISE USING MESSAGE := format('Specified scale % is invalid.', p_fractions), + DETAIL := format('Source value is out of %s data type range.', v_err_message), + HINT := 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; + +CREATE OR REPLACE FUNCTION sys.TODATETIMEOFFSET(IN input_expr PG_CATALOG.TEXT , IN tz_offset TEXT) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + v_string pg_catalog.text; + v_sign pg_catalog.text; + str_hr TEXT; + str_mi TEXT; + precision_str TEXT; + sign_flag INTEGER; + v_hr INTEGER; + v_mi INTEGER; + v_precision INTEGER; + input_expr_datetime2 datetime2; +BEGIN + + BEGIN + input_expr_datetime2 := cast(input_expr as sys.datetime2); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + IF input_expr IS NULL or tz_offset IS NULL THEN + RETURN NULL; + END IF; + + IF tz_offset LIKE '+__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := 1; + ELSIF tz_offset LIKE '-__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := -1; + ELSE + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + BEGIN + v_hr := str_hr::INTEGER; + v_mi := str_mi ::INTEGER; + exception + WHEN others THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END; + + + if v_hr > 14 or (v_hr = 14 and v_mi > 0) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + v_hr := v_hr * sign_flag; + + v_string := CONCAT(input_expr_datetime2::pg_catalog.text , tz_offset); + + BEGIN + RETURN cast(v_string as sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + + +CREATE OR REPLACE FUNCTION sys.TODATETIMEOFFSET(IN input_expr PG_CATALOG.TEXT , IN tz_offset anyelement) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + v_string pg_catalog.text; + v_sign pg_catalog.text; + hr INTEGER; + mi INTEGER; + tz_sign INTEGER; + tz_offset_smallint INTEGER; + input_expr_datetime2 datetime2; +BEGIN + + BEGIN + input_expr_datetime2:= cast(input_expr as sys.datetime2); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + + IF pg_typeof(tz_offset) NOT 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 ,'varbinary'::regtype) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + BEGIN + IF pg_typeof(tz_offset) NOT IN ('varbinary'::regtype) THEN + tz_offset := FLOOR(tz_offset); + END IF; + tz_offset_smallint := cast(tz_offset AS smallint); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Arithmetic overflow error converting expression to data type smallint.'; + END; + + IF input_expr IS NULL THEN + RETURN NULL; + END IF; + + IF tz_offset_smallint < 0 THEN + tz_sign := 1; + ELSE + tz_sign := 0; + END IF; + + IF tz_offset_smallint > 840 or tz_offset_smallint < -840 THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + hr := tz_offset_smallint / 60; + mi := tz_offset_smallint % 60; + + v_sign := ( + SELECT CASE + WHEN (tz_sign) = 1 + THEN '-' + WHEN (tz_sign) = 0 + THEN '+' + END + ); + + + v_string := CONCAT(input_expr_datetime2::pg_catalog.text,v_sign,abs(hr)::SMALLINT::text,':', + abs(mi)::SMALLINT::text); + + BEGIN + RETURN cast(v_string as sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +ALTER FUNCTION sys.power(IN arg1 BIGINT, IN arg2 NUMERIC) STRICT; + +ALTER FUNCTION sys.power(IN arg1 INT, IN arg2 NUMERIC) STRICT; + +ALTER FUNCTION sys.power(IN arg1 SMALLINT, IN arg2 NUMERIC) STRICT; + +ALTER FUNCTION sys.power(IN arg1 TINYINT, IN arg2 NUMERIC) STRICT; + +-- Update data-type of information_schema_tsql.TABLE_TYPE to sys.varchar if it's data-type is pg_catalog.varchar +DO +$$ +BEGIN + + IF EXISTS( + SELECT 1 + FROM information_schema.columns + WHERE table_schema='information_schema_tsql' + AND table_name='tables' + AND column_name='TABLE_TYPE' + AND udt_schema='pg_catalog' + AND udt_name='varchar' + ) THEN + ALTER VIEW information_schema_tsql.tables RENAME TO tables_deprecated_in_3_4_0; + + CREATE OR REPLACE VIEW information_schema_tsql.tables AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST( + CASE WHEN c.reloptions[1] LIKE 'bbf_original_rel_name%' THEN substring(c.reloptions[1], 23) + ELSE c.relname END + AS sys._ci_sysname) AS "TABLE_NAME", + + CAST( + CASE WHEN c.relkind IN ('r', 'p') THEN 'BASE TABLE' + WHEN c.relkind = 'v' THEN 'VIEW' + ELSE null END + AS sys.varchar(10)) COLLATE sys.database_default AS "TABLE_TYPE" + + FROM sys.pg_namespace_ext nc JOIN pg_class c ON (nc.oid = c.relnamespace) + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname + + WHERE c.relkind IN ('r', 'v', 'p') + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) + AND ext.dbid = cast(sys.db_id() as oid) + AND (NOT c.relname = 'sysdatabases'); + + GRANT SELECT ON information_schema_tsql.tables TO PUBLIC; + + CALL sys.babelfish_drop_deprecated_object('view', 'information_schema_tsql', 'tables_deprecated_in_3_4_0'); + END IF; +END +$$ +LANGUAGE plpgsql; + + +-- Matches and returns column length of the corresponding column of the given table +CREATE OR REPLACE FUNCTION sys.COL_LENGTH(IN object_name TEXT, IN column_name TEXT) +RETURNS SMALLINT AS $BODY$ +DECLARE + col_name TEXT; + object_id oid; + column_id INT; + column_length SMALLINT; + column_data_type TEXT; + typeid oid; + typelen INT; + typemod INT; +BEGIN + -- Get the object ID for the provided object_name + object_id := sys.OBJECT_ID(object_name, 'U'); + IF object_id IS NULL THEN + RETURN NULL; + END IF; + + -- Truncate and normalize the column name + col_name := sys.babelfish_truncate_identifier(sys.babelfish_remove_delimiter_pair(lower(column_name))); + + -- Get the column ID, typeid, length, and typmod for the provided column_name + SELECT attnum, a.atttypid, a.attlen, a.atttypmod + INTO column_id, typeid, typelen, typemod + FROM pg_attribute a + WHERE attrelid = object_id AND lower(attname) = col_name COLLATE sys.database_default; + + IF column_id IS NULL THEN + RETURN NULL; + END IF; + + -- Get the correct data type + column_data_type := sys.translate_pg_type_to_tsql(typeid); + + IF column_data_type = 'sysname' THEN + column_length := 256; + ELSIF column_data_type IS NULL THEN + + -- Check if it's a user-defined data type + SELECT sys.translate_pg_type_to_tsql(typbasetype), typlen, typtypmod + INTO column_data_type, typelen, typemod + FROM pg_type + WHERE oid = typeid; + + IF column_data_type = 'sysname' THEN + column_length := 256; + ELSE + -- Calculate column length based on base type information + column_length := sys.tsql_type_max_length_helper(column_data_type, typelen, typemod); + END IF; + ELSE + -- Calculate column length based on base type information + column_length := sys.tsql_type_max_length_helper(column_data_type, typelen, typemod); + END IF; + + RETURN column_length; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE +STRICT; + +-- Matches and returns column name of the corresponding table +CREATE OR REPLACE FUNCTION sys.COL_NAME(IN table_id INT, IN column_id INT) +RETURNS sys.SYSNAME AS $$ + DECLARE + column_name TEXT; + BEGIN + SELECT attname INTO STRICT column_name + FROM pg_attribute + WHERE attrelid = table_id AND attnum = column_id AND attnum > 0; + + RETURN column_name::sys.SYSNAME; + EXCEPTION + WHEN OTHERS THEN + RETURN NULL; + END; +$$ +LANGUAGE plpgsql IMMUTABLE +STRICT; + +CREATE OR REPLACE FUNCTION SYS.TYPE_NAME(IN type_id INT) +RETURNS SYS.NVARCHAR(128) AS +'babelfishpg_tsql', 'type_name' +LANGUAGE C STABLE; + +CREATE OR REPLACE FUNCTION SYS.TYPE_ID(IN type_name SYS.NVARCHAR) +RETURNS INT AS +'babelfishpg_tsql', 'type_id' +LANGUAGE C STABLE; + +CREATE OR REPLACE FUNCTION sys.SWITCHOFFSET(IN input_expr PG_CATALOG.TEXT, + IN tz_offset PG_CATALOG.TEXT) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + p_year INTEGER; + p_month INTEGER; + p_day INTEGER; + p_hour INTEGER; + p_minute INTEGER; + p_seconds INTEGER; + p_nanosecond PG_CATALOG.TEXT; + p_tzoffset INTEGER; + f_tzoffset INTEGER; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + offset_str PG_CATALOG.TEXT; + v_resdatetimeupdated TIMESTAMP WITHOUT TIME ZONE; + tzfm INTEGER; + str_hr PG_CATALOG.TEXT; + str_mi PG_CATALOG.TEXT; + v_hr INTEGER; + v_mi INTEGER; + sign_flag INTEGER; + v_string pg_catalog.text; + isoverflow pg_catalog.text; +BEGIN + + BEGIN + p_year := date_part('year',input_expr::TIMESTAMP); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + if p_year <1 or p_year > 9999 THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END IF; + + + BEGIN + input_expr:= cast(input_expr AS datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + IF input_expr IS NULL or tz_offset IS NULL THEN + RETURN NULL; + END IF; + + + IF tz_offset LIKE '+__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := 1; + ELSIF tz_offset LIKE '-__:__' THEN + str_hr := SUBSTRING(tz_offset,2,2); + str_mi := SUBSTRING(tz_offset,5,2); + sign_flag := -1; + ELSE + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + + + BEGIN + v_hr := str_hr::INTEGER; + v_mi := str_mi::INTEGER; + exception + WHEN others THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END; + + if v_hr > 14 or (v_hr = 14 and v_mi > 0) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + tzfm := sign_flag*((v_hr*60)+v_mi); + + p_year := date_part('year',input_expr::TIMESTAMP); + p_month := date_part('month',input_expr::TIMESTAMP); + p_day := date_part('day',input_expr::TIMESTAMP); + p_hour := date_part('hour',input_expr::TIMESTAMP); + p_minute := date_part('minute',input_expr::TIMESTAMP); + p_seconds := TRUNC(date_part('second', input_expr::TIMESTAMP))::INTEGER; + p_tzoffset := -1*sys.babelfish_get_datetimeoffset_tzoffset(cast(input_expr as sys.datetimeoffset))::integer; + + p_nanosecond := split_part(input_expr COLLATE "C",'.',2); + p_nanosecond := split_part(p_nanosecond COLLATE "C",' ',1); + + + f_tzoffset := p_tzoffset + tzfm; + + v_resdatetime := make_timestamp(p_year,p_month,p_day,p_hour,p_minute,p_seconds); + v_resdatetimeupdated := v_resdatetime + make_interval(mins => f_tzoffset); + + isoverflow := split_part(v_resdatetimeupdated::TEXT COLLATE "C",' ',3); + + v_string := CONCAT(v_resdatetimeupdated::pg_catalog.text,'.',p_nanosecond::text,tz_offset); + p_year := split_part(v_string COLLATE "C",'-',1)::INTEGER; + + + if p_year <1 or p_year > 9999 or isoverflow = 'BC' THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.'; + END IF; + + BEGIN + RETURN cast(v_string AS sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.SWITCHOFFSET(IN input_expr PG_CATALOG.TEXT, + IN tz_offset anyelement) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + p_year INTEGER; + p_month INTEGER; + p_day INTEGER; + p_hour INTEGER; + p_minute INTEGER; + p_seconds INTEGER; + p_nanosecond PG_CATALOG.TEXT; + p_tzoffset INTEGER; + f_tzoffset INTEGER; + v_resdatetime TIMESTAMP WITHOUT TIME ZONE; + offset_str PG_CATALOG.TEXT; + v_resdatetimeupdated TIMESTAMP WITHOUT TIME ZONE; + tzfm INTEGER; + str_hr PG_CATALOG.TEXT; + str_mi PG_CATALOG.TEXT; + v_hr INTEGER; + v_mi INTEGER; + sign_flag INTEGER; + v_string pg_catalog.text; + v_sign PG_CATALOG.TEXT; + tz_offset_smallint smallint; + isoverflow pg_catalog.text; +BEGIN + + IF pg_typeof(tz_offset) NOT 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,'varbinary'::regtype ) THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + BEGIN + p_year := date_part('year',input_expr::TIMESTAMP); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + + if p_year <1 or p_year > 9999 THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END IF; + + BEGIN + input_expr:= cast(input_expr AS datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + + BEGIN + IF pg_typeof(tz_offset) NOT IN ('varbinary'::regtype) THEN + tz_offset := FLOOR(tz_offset); + END IF; + tz_offset_smallint := cast(tz_offset AS smallint); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Arithmetic overflow error converting expression to data type smallint.'; + END; + + IF input_expr IS NULL THEN + RETURN NULL; + END IF; + + if tz_offset_smallint > 840 or tz_offset_smallint < -840 THEN + RAISE EXCEPTION 'The timezone provided to builtin function todatetimeoffset is invalid.'; + END IF; + + v_hr := tz_offset_smallint/60; + v_mi := tz_offset_smallint%60; + + + p_year := date_part('year',input_expr::TIMESTAMP); + p_month := date_part('month',input_expr::TIMESTAMP); + p_day := date_part('day',input_expr::TIMESTAMP); + p_hour := date_part('hour',input_expr::TIMESTAMP); + p_minute := date_part('minute',input_expr::TIMESTAMP); + p_seconds := TRUNC(date_part('second', input_expr::TIMESTAMP))::INTEGER; + p_tzoffset := -1*sys.babelfish_get_datetimeoffset_tzoffset(cast(input_expr as sys.datetimeoffset))::integer; + + v_sign := ( + SELECT CASE + WHEN (tz_offset_smallint) >= 0 + THEN '+' + ELSE '-' + END + ); + + p_nanosecond := split_part(input_expr COLLATE "C",'.',2); + p_nanosecond := split_part(p_nanosecond COLLATE "C",' ',1); + + f_tzoffset := p_tzoffset + tz_offset_smallint; + v_resdatetime := make_timestamp(p_year,p_month,p_day,p_hour,p_minute,p_seconds); + v_resdatetimeupdated := v_resdatetime + make_interval(mins => f_tzoffset); + + isoverflow := split_part(v_resdatetimeupdated::TEXT COLLATE "C",' ',3); + + v_string := CONCAT(v_resdatetimeupdated::pg_catalog.text,'.',p_nanosecond::text,v_sign,abs(v_hr)::TEXT,':',abs(v_mi)::TEXT); + + p_year := split_part(v_string COLLATE "C",'-',1)::INTEGER; + + if p_year <1 or p_year > 9999 or isoverflow = 'BC' THEN + RAISE USING MESSAGE := 'The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.'; + END IF; + + + BEGIN + RETURN cast(v_string AS sys.datetimeoffset); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + + +CREATE OR REPLACE FUNCTION sys.DATETRUNC(IN datepart PG_CATALOG.TEXT, IN date ANYELEMENT) RETURNS ANYELEMENT AS +$body$ +DECLARE + days_offset INT; + v_day INT; + result_date timestamp; + input_expr_timestamp timestamp; + date_arg_datatype regtype; + offset_string PG_CATALOG.TEXT; + datefirst_value INT; +BEGIN + BEGIN + /* perform input validation */ + date_arg_datatype := pg_typeof(date); + IF datepart NOT IN ('year', 'quarter', 'month', 'week', 'tsql_week', 'hour', 'minute', 'second', 'millisecond', 'microsecond', + 'doy', 'day', 'nanosecond', 'tzoffset') THEN + RAISE EXCEPTION '''%'' is not a recognized datetrunc option.', datepart; + ELSIF date_arg_datatype NOT IN ('date'::regtype, 'time'::regtype, 'sys.datetime'::regtype, 'sys.datetime2'::regtype, + 'sys.datetimeoffset'::regtype, 'sys.smalldatetime'::regtype) THEN + RAISE EXCEPTION 'Argument data type ''%'' is invalid for argument 2 of datetrunc function.', date_arg_datatype; + ELSIF datepart IN ('nanosecond', 'tzoffset') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''%''.',datepart, date_arg_datatype; + ELSIF datepart IN ('dow') THEN + RAISE EXCEPTION 'The datepart ''weekday'' is not supported by date function datetrunc for data type ''%''.', date_arg_datatype; + ELSIF date_arg_datatype = 'date'::regtype AND datepart IN ('hour', 'minute', 'second', 'millisecond', 'microsecond') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''date''.', datepart; + ELSIF date_arg_datatype = 'datetime'::regtype AND datepart IN ('microsecond') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''datetime''.', datepart; + ELSIF date_arg_datatype = 'smalldatetime'::regtype AND datepart IN ('millisecond', 'microsecond') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''smalldatetime''.', datepart; + ELSIF date_arg_datatype = 'time'::regtype THEN + IF datepart IN ('year', 'quarter', 'month', 'doy', 'day', 'week', 'tsql_week') THEN + RAISE EXCEPTION 'The datepart ''%'' is not supported by date function datetrunc for data type ''time''.', datepart; + END IF; + -- Limitation in determining if the specified fractional scale (if provided any) for time datatype is + -- insufficient to support provided datepart (millisecond, microsecond) value + ELSIF date_arg_datatype IN ('datetime2'::regtype, 'datetimeoffset'::regtype) THEN + -- Limitation in determining if the specified fractional scale (if provided any) for the above datatype is + -- insufficient to support for provided datepart (millisecond, microsecond) value + END IF; + + /* input validation is complete, proceed with result calculation. */ + IF date_arg_datatype = 'time'::regtype THEN + RETURN date_trunc(datepart, date); + ELSE + input_expr_timestamp = date::timestamp; + -- preserving offset_string value in the case of datetimeoffset datatype before converting it to timestamps + IF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + offset_string = RIGHT(date::PG_CATALOG.TEXT, 6); + input_expr_timestamp := LEFT(date::PG_CATALOG.TEXT, -6)::timestamp; + END IF; + CASE + WHEN datepart IN ('year', 'quarter', 'month', 'week', 'hour', 'minute', 'second', 'millisecond', 'microsecond') THEN + result_date := date_trunc(datepart, input_expr_timestamp); + WHEN datepart IN ('doy', 'day') THEN + result_date := date_trunc('day', input_expr_timestamp); + WHEN datepart IN ('tsql_week') THEN + -- sql server datepart 'iso_week' is similar to postgres 'week' datepart + -- handle sql server datepart 'week' here based on the value of set variable 'DATEFIRST' + v_day := EXTRACT(dow from input_expr_timestamp)::INT; + datefirst_value := current_setting('babelfishpg_tsql.datefirst')::INT; + IF v_day = 0 THEN + v_day := 7; + END IF; + result_date := date_trunc('day', input_expr_timestamp); + days_offset := (7 + v_day - datefirst_value)%7; + result_date := result_date - make_interval(days => days_offset); + END CASE; + -- concat offset_string to result_date in case of datetimeoffset before converting it to datetimeoffset datatype. + IF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + RETURN concat(result_date, ' ', offset_string)::sys.datetimeoffset; + ELSE + RETURN result_date; + END IF; + END IF; + END; +END; +$body$ +LANGUAGE plpgsql STABLE; + +-- another definition of datetrunc as anyelement can not handle unknown type. +CREATE OR REPLACE FUNCTION sys.DATETRUNC(IN datepart PG_CATALOG.TEXT, IN date PG_CATALOG.TEXT) RETURNS SYS.DATETIME2 AS +$body$ +DECLARE + input_expr_datetime2 sys.datetime2; +BEGIN + IF datepart NOT IN ('year', 'quarter', 'month', 'week', 'tsql_week', 'hour', 'minute', 'second', 'millisecond', 'microsecond', + 'doy', 'day', 'nanosecond', 'tzoffset') THEN + RAISE EXCEPTION '''%'' is not a recognized datetrunc option.', datepart; + END IF; + BEGIN + input_expr_datetime2 := cast(date as sys.datetime2); + exception + WHEN others THEN + RAISE USING MESSAGE := 'Conversion failed when converting date and/or time from character string.'; + END; + IF input_expr_datetime2 IS NULL THEN + RETURN NULL; + ELSE + -- input string literal is valid, call the datetrunc function with datetime2 datatype. + RETURN sys.DATETRUNC(datepart, input_expr_datetime2); + END IF; +END; +$body$ +LANGUAGE plpgsql STABLE; + +-- BABELFISH_SCHEMA_PERMISSIONS +CREATE TABLE IF NOT EXISTS sys.babelfish_schema_permissions ( + dbid smallint NOT NULL, + schema_name NAME NOT NULL, + object_name NAME NOT NULL, + permission NAME NOT NULL, + grantee NAME NOT NULL, + object_type NAME, + PRIMARY KEY(dbid, schema_name, object_name, permission, grantee) +); + +create or replace function sys.babelfish_timezone_mapping(IN tmz text) returns text +AS 'babelfishpg_tsql', 'timezone_mapping' +LANGUAGE C IMMUTABLE ; + +CREATE OR REPLACE FUNCTION sys.timezone(IN tzzone PG_CATALOG.TEXT , IN input_expr PG_CATALOG.TEXT) +RETURNS sys.datetimeoffset +AS +$BODY$ +BEGIN + IF input_expr = 'NULL' THEN + RAISE USING MESSAGE := 'Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.'; + END IF; + + IF input_expr IS NULL OR tzzone IS NULL THEN + RETURN NULL; + END IF; + + RAISE USING MESSAGE := 'Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.'; +END; +$BODY$ +LANGUAGE plpgsql +IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.timezone(IN tzzone PG_CATALOG.TEXT , IN input_expr anyelement) +RETURNS sys.datetimeoffset +AS +$BODY$ +DECLARE + tz_offset PG_CATALOG.TEXT; + tz_name PG_CATALOG.TEXT; + lower_tzn PG_CATALOG.TEXT; + prev_res PG_CATALOG.TEXT; + result PG_CATALOG.TEXT; + is_dstt bool; + tz_diff PG_CATALOG.TEXT; + input_expr_tx PG_CATALOG.TEXT; + input_expr_tmz TIMESTAMPTZ; +BEGIN + IF input_expr IS NULL OR tzzone IS NULL THEN + RETURN NULL; + END IF; + + lower_tzn := lower(tzzone); + IF lower_tzn <> 'utc' THEN + tz_name := sys.babelfish_timezone_mapping(lower_tzn); + ELSE + tz_name := 'utc'; + END IF; + + IF tz_name = 'NULL' THEN + RAISE USING MESSAGE := format('Argument data type or the parameter %s provided to AT TIME ZONE clause is invalid.', tzzone); + END IF; + + IF pg_typeof(input_expr) IN ('sys.smalldatetime'::regtype, 'sys.datetime'::regtype, 'sys.datetime2'::regtype) THEN + input_expr_tx := input_expr::TEXT; + input_expr_tmz := input_expr_tx :: TIMESTAMPTZ; + + result := (SELECT input_expr_tmz AT TIME ZONE tz_name)::TEXT; + tz_diff := (SELECT result::TIMESTAMPTZ - input_expr_tmz)::TEXT; + if LEFT(tz_diff,1) <> '-' THEN + tz_diff := concat('+',tz_diff); + END IF; + tz_offset := left(tz_diff,6); + input_expr_tx := concat(input_expr_tx,tz_offset); + return cast(input_expr_tx as sys.datetimeoffset); + ELSIF pg_typeof(input_expr) = 'sys.DATETIMEOFFSET'::regtype THEN + input_expr_tx := input_expr::TEXT; + input_expr_tmz := input_expr_tx :: TIMESTAMPTZ; + result := (SELECT input_expr_tmz AT TIME ZONE tz_name)::TEXT; + tz_diff := (SELECT result::TIMESTAMPTZ - input_expr_tmz)::TEXT; + if LEFT(tz_diff,1) <> '-' THEN + tz_diff := concat('+',tz_diff); + END IF; + tz_offset := left(tz_diff,6); + result := concat(result,tz_offset); + return cast(result as sys.datetimeoffset); + ELSE + RAISE USING MESSAGE := 'Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.'; + END IF; + +END; +$BODY$ +LANGUAGE 'plpgsql' STABLE; + +CREATE OR REPLACE FUNCTION sys.sysutcdatetime() returns sys.datetime2 +AS 'babelfishpg_tsql', 'sysutcdatetime' +LANGUAGE C STABLE; + +create or replace function sys.getutcdate() returns sys.datetime +AS 'babelfishpg_tsql', 'getutcdate' +LANGUAGE C STABLE; + +-- Cast functions from datettime to numeric types +CREATE OR REPLACE FUNCTION sys.datetime_to_bit(IN arg sys.DATETIME) +RETURNS SYS.BIT +AS 'babelfishpg_common', 'datetime_to_bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_int2(IN arg sys.DATETIME) +RETURNS INT2 +AS 'babelfishpg_common', 'datetime_to_int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_int4(IN arg sys.DATETIME) +RETURNS INT4 +AS 'babelfishpg_common', 'datetime_to_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_int8(IN arg sys.DATETIME) +RETURNS INT8 +AS 'babelfishpg_common', 'datetime_to_int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_float4(IN arg sys.DATETIME) +RETURNS float4 +AS 'babelfishpg_common', 'datetime_to_float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_float8(IN arg sys.DATETIME) +RETURNS float8 +AS 'babelfishpg_common', 'datetime_to_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datetime_to_numeric(IN arg sys.DATETIME) +RETURNS NUMERIC +AS 'babelfishpg_common', 'datetime_to_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- Cast functions from smalldatetoime to numeric types +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_bit(IN arg sys.SMALLDATETIME) +RETURNS SYS.BIT +AS 'babelfishpg_common', 'smalldatetime_to_bit' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_int2(IN arg sys.SMALLDATETIME) +RETURNS INT2 +AS 'babelfishpg_common', 'smalldatetime_to_int2' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_int4(IN arg sys.SMALLDATETIME) +RETURNS INT4 +AS 'babelfishpg_common', 'smalldatetime_to_int4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_int8(IN arg sys.SMALLDATETIME) +RETURNS INT8 +AS 'babelfishpg_common', 'smalldatetime_to_int8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_float4(IN arg sys.SMALLDATETIME) +RETURNS float4 +AS 'babelfishpg_common', 'smalldatetime_to_float4' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_float8(IN arg sys.SMALLDATETIME) +RETURNS float8 +AS 'babelfishpg_common', 'smalldatetime_to_float8' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.smalldatetime_to_numeric(IN arg sys.SMALLDATETIME) +RETURNS NUMERIC +AS 'babelfishpg_common', 'smalldatetime_to_numeric' +LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- internal helper function for date_bucket(). +CREATE OR REPLACE FUNCTION sys.date_bucket_internal_helper(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN check_date boolean, IN origin boolean, IN date ANYELEMENT default NULL) RETURNS boolean +AS +$body$ +DECLARE + date_arg_datatype regtype; +BEGIN + date_arg_datatype := pg_typeof(date); + IF datepart NOT IN ('year', 'quarter', 'month', 'week', 'doy', 'day', 'hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond') THEN + RAISE EXCEPTION '% is not a recognized date_bucket option.', datepart; + + -- Check for NULL value of number argument + ELSIF number IS NULL THEN + RAISE EXCEPTION 'Argument data type NULL is invalid for argument 2 of date_bucket function.'; + + ELSIF check_date IS NULL THEN + RAISE EXCEPTION 'Argument data type NULL is invalid for argument 3 of date_bucket function.'; + + ELSIF check_date IS false THEN + RAISE EXCEPTION 'Argument data type % is invalid for argument 3 of date_bucket function.', date_arg_datatype; + + ELSIF check_date IS true THEN + IF date_arg_datatype NOT IN ('sys.datetime'::regtype, 'sys.datetime2'::regtype, 'sys.datetimeoffset'::regtype, 'sys.smalldatetime'::regtype, 'date'::regtype, 'time'::regtype) THEN + RAISE EXCEPTION 'Argument data type % is invalid for argument 3 of date_bucket function.', date_arg_datatype; + ELSIF datepart IN ('doy', 'microsecond', 'nanosecond') THEN + RAISE EXCEPTION 'The datepart % is not supported by date function date_bucket for data type %.', datepart, date_arg_datatype; + ELSIF date_arg_datatype = 'date'::regtype AND datepart IN ('hour', 'minute', 'second', 'millisecond') THEN + RAISE EXCEPTION 'The datepart % is not supported by date function date_bucket for data type ''date''.', datepart; + ELSIF date_arg_datatype = 'time'::regtype AND datepart IN ('year', 'quarter', 'month', 'day', 'week') THEN + RAISE EXCEPTION 'The datepart % is not supported by date function date_bucket for data type ''time''.', datepart; + ELSIF origin IS false THEN + RAISE EXCEPTION 'Argument data type varchar is invalid for argument 4 of date_bucket function.'; + ELSIF number <= 0 THEN + RAISE EXCEPTION 'Invalid bucket width value passed to date_bucket function. Only positive values are allowed.'; + END IF; + RETURN true; + ELSE + RAISE EXCEPTION 'Argument data type varchar is invalid for argument 3 of date_bucket function.'; + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- Another definition of date_bucket() with arg PG_CATALOG.TEXT since ANYELEMENT cannot handle type unknown. +CREATE OR REPLACE FUNCTION sys.date_bucket(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN date PG_CATALOG.TEXT, IN origin PG_CATALOG.TEXT default NULL) RETURNS PG_CATALOG.TEXT +AS +$body$ +DECLARE +BEGIN + IF date IS NULL THEN + -- check_date is NULL when date is NULL + -- check_date is false when we are sure that date can not be a valid datatype. + -- check_date is true when date might be valid datatype so check is required. + RETURN sys.date_bucket_internal_helper(datepart, number, NULL, false, 'NULL'::text); + ELSE + RETURN sys.date_bucket_internal_helper(datepart, number, false, NULL, date); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- Another definition of date_bucket() with arg date of type ANYELEMENT and origin of type TEXT. +CREATE OR REPLACE FUNCTION sys.date_bucket(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN date ANYELEMENT, IN origin PG_CATALOG.TEXT) RETURNS ANYELEMENT +AS +$body$ +DECLARE +BEGIN + IF date IS NULL THEN + RETURN sys.date_bucket_internal_helper(datepart, number, NULL, NULL, 'NULL'::text); + ELSIF pg_typeof(date) IN ('sys.datetime'::regtype, 'sys.datetime2'::regtype, 'sys.datetimeoffset'::regtype, 'sys.smalldatetime'::regtype, 'date'::regtype, 'time'::regtype) THEN + IF origin IS NULL THEN + RETURN sys.date_bucket(datepart, number, date); + ELSE + RETURN sys.date_bucket_internal_helper(datepart, number, true, false, date); + END IF; + ELSE + RETURN sys.date_bucket_internal_helper(datepart, number, false, NULL, date); + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.date_bucket(IN datepart PG_CATALOG.TEXT, IN number INTEGER, IN date ANYELEMENT, IN origin ANYELEMENT default NULL) RETURNS ANYELEMENT +AS +$body$ +DECLARE + required_bucket INT; + years_diff INT; + quarters_diff INT; + months_diff INT; + hours_diff INT; + minutes_diff INT; + seconds_diff INT; + milliseconds_diff INT; + timezone INT; + result_time time; + result_date timestamp; + offset_string PG_CATALOG.text; + date_difference_interval INTERVAL; + millisec_trunc_diff_interval INTERVAL; + date_arg_datatype regtype; + is_valid boolean; +BEGIN + BEGIN + date_arg_datatype := pg_typeof(date); + is_valid := sys.date_bucket_internal_helper(datepart, number, true, true, date); + + -- If optional argument origin's value is not provided by user then set it's default value of valid datatype. + IF origin IS NULL THEN + IF date_arg_datatype = 'sys.datetime'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.datetime); + ELSIF date_arg_datatype = 'sys.datetime2'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.datetime2); + ELSIF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.datetimeoffset); + ELSIF date_arg_datatype = 'sys.smalldatetime'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS sys.smalldatetime); + ELSIF date_arg_datatype = 'date'::regtype THEN + origin := CAST('1900-01-01 00:00:00.000' AS pg_catalog.date); + ELSIF date_arg_datatype = 'time'::regtype THEN + origin := CAST('00:00:00.000' AS pg_catalog.time); + END IF; + END IF; + END; + + /* support of date_bucket() for different kinds of date datatype starts here */ + -- support of date_bucket() when date is of 'time' datatype + IF date_arg_datatype = 'time'::regtype THEN + -- Find interval between date and origin and extract hour, minute, second, millisecond from the interval + date_difference_interval := date_trunc('millisecond', date) - date_trunc('millisecond', origin); + hours_diff := EXTRACT('hour' from date_difference_interval)::INT; + minutes_diff := EXTRACT('minute' from date_difference_interval)::INT; + seconds_diff := FLOOR(EXTRACT('second' from date_difference_interval))::INT; + milliseconds_diff := FLOOR(EXTRACT('millisecond' from date_difference_interval))::INT; + CASE datepart + WHEN 'hour' THEN + -- Here we are finding how many buckets we have to add in the origin so that we can reach to a bucket in which date belongs. + -- For cases where origin > date, we might end up in a bucket which exceeds date by 1 bucket. + -- For Ex. 'date_bucket(hour, 2, '01:00:00', '08:00:00')' hence check if the result_time is greater then date + -- For comparision we are trunceting the result_time to milliseconds + required_bucket := hours_diff/number; + result_time := origin + make_interval(hours => required_bucket * number); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(hours => number); + END IF; + RETURN result_time; + + WHEN 'minute' THEN + required_bucket := (hours_diff * 60 + minutes_diff)/number; + result_time := origin + make_interval(mins => required_bucket * number); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(mins => number); + END IF; + RETURN result_time; + + WHEN 'second' THEN + required_bucket := ((hours_diff * 60 + minutes_diff) * 60 + seconds_diff)/number; + result_time := origin + make_interval(secs => required_bucket * number); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(secs => number); + END IF; + RETURN result_time; + + WHEN 'millisecond' THEN + required_bucket := (((hours_diff * 60 + minutes_diff) * 60) * 1000 + milliseconds_diff)/number; + result_time := origin + make_interval(secs => ((required_bucket * number)::numeric) * 0.001); + IF date_trunc('millisecond', result_time) > date THEN + RETURN result_time - make_interval(secs => (number::numeric) * 0.001); + END IF; + RETURN result_time; + END CASE; + + -- support of date_bucket() when date is of {'datetime2', 'datetimeoffset'} datatype + -- handling separately because both the datatypes have precision in milliseconds + ELSIF date_arg_datatype IN ('sys.datetime2'::regtype, 'sys.datetimeoffset'::regtype) THEN + -- when datepart is {year, quarter, month} make use of AGE() function to find number of buckets + IF datepart IN ('year', 'quarter', 'month') THEN + date_difference_interval := AGE(date_trunc('day', date::timestamp), date_trunc('day', origin::timestamp)); + years_diff := EXTRACT('Year' from date_difference_interval)::INT; + months_diff := EXTRACT('Month' from date_difference_interval)::INT; + CASE datepart + WHEN 'year' THEN + -- Here we are finding how many buckets we have to add in the origin so that we can reach to a bucket in which date belongs. + -- For cases where origin > date, we might end up in a bucket which exceeds date by 1 bucket. + -- For Ex. date_bucket(year, 2, '2010-01-01', '2019-01-01')) hence check if the result_time is greater then date. + -- For comparision we are trunceting the result_time to milliseconds + required_bucket := years_diff/number; + result_date := origin::timestamp + make_interval(years => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(years => number); + END IF; + + WHEN 'month' THEN + required_bucket := (12 * years_diff + months_diff)/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number); + END IF; + + WHEN 'quarter' THEN + quarters_diff := (12 * years_diff + months_diff)/3; + required_bucket := quarters_diff/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number * 3); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number*3); + END IF; + END CASE; + + -- when datepart is {week, day, hour, minute, second, millisecond} make use of built-in date_bin() postgresql function. + ELSE + -- trunceting origin to millisecond before passing it to date_bin() function. + -- store the difference between origin and trunceted origin to add it in the result of date_bin() function + date_difference_interval := concat(number, ' ', datepart)::INTERVAL; + millisec_trunc_diff_interval := (origin::timestamp - date_trunc('millisecond', origin::timestamp))::interval; + result_date = date_bin(date_difference_interval, date::timestamp, date_trunc('millisecond', origin::timestamp)) + millisec_trunc_diff_interval; + + -- Filetering cases where the required bucket ends at date then date_bin() gives start point of this bucket as result. + IF result_date + date_difference_interval <= date::timestamp THEN + result_date = result_date + date_difference_interval; + END IF; + END IF; + + -- All the above operations are performed by converting every date datatype into TIMESTAMPS. + -- datetimeoffset is typecasted into TIMESTAMPS that changes the value. + -- Ex. '2023-02-23 09:19:21.23 +10:12'::sys.datetimeoffset::timestamp => '2023-02-22 23:07:21.23' + -- The output of date_bucket() for datetimeoffset datatype will always be in the same time-zone as of provided date argument. + -- Here, converting TIMESTAMP into datetimeoffset datatype with the same timezone as of date argument. + IF date_arg_datatype = 'sys.datetimeoffset'::regtype THEN + timezone = sys.babelfish_get_datetimeoffset_tzoffset(date)::INTEGER; + offset_string = right(date::PG_CATALOG.TEXT, 6); + result_date = result_date + make_interval(mins => timezone); + RETURN concat(result_date, ' ', offset_string)::sys.datetimeoffset; + ELSE + RETURN result_date; + END IF; + + -- support of date_bucket() when date is of {'date', 'datetime', 'smalldatetime'} datatype + ELSE + -- Round datetime to fixed bins (e.g. .000, .003, .007) + IF date_arg_datatype = 'sys.datetime'::regtype THEN + date := sys.babelfish_conv_string_to_datetime('DATETIME', date::TEXT)::sys.datetime; + origin := sys.babelfish_conv_string_to_datetime('DATETIME', origin::TEXT)::sys.datetime; + END IF; + -- when datepart is {year, quarter, month} make use of AGE() function to find number of buckets + IF datepart IN ('year', 'quarter', 'month') THEN + date_difference_interval := AGE(date_trunc('day', date::timestamp), date_trunc('day', origin::timestamp)); + years_diff := EXTRACT('Year' from date_difference_interval)::INT; + months_diff := EXTRACT('Month' from date_difference_interval)::INT; + CASE datepart + WHEN 'year' THEN + -- Here we are finding how many buckets we have to add in the origin so that we can reach to a bucket in which date belongs. + -- For cases where origin > date, we might end up in a bucket which exceeds date by 1 bucket. + -- For Example. date_bucket(year, 2, '2010-01-01', '2019-01-01') hence check if the result_time is greater then date. + -- For comparision we are trunceting the result_time to milliseconds + required_bucket := years_diff/number; + result_date := origin::timestamp + make_interval(years => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(years => number); + END IF; + + WHEN 'month' THEN + required_bucket := (12 * years_diff + months_diff)/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number); + END IF; + + WHEN 'quarter' THEN + quarters_diff := (12 * years_diff + months_diff)/3; + required_bucket := quarters_diff/number; + result_date := origin::timestamp + make_interval(months => required_bucket * number * 3); + IF result_date > date::timestamp THEN + result_date = result_date - make_interval(months => number * 3); + END IF; + END CASE; + RETURN result_date; + + -- when datepart is {week, day, hour, minute, second, millisecond} make use of built-in date_bin() postgresql function. + ELSE + -- trunceting origin to millisecond before passing it to date_bin() function. + -- store the difference between origin and trunceted origin to add it in the result of date_bin() function + date_difference_interval := concat(number, ' ', datepart)::INTERVAL; + result_date = date_bin(date_difference_interval, date::TIMESTAMP, origin::TIMESTAMP); + -- Filetering cases where the required bucket ends at date then date_bin() gives start point of this bucket as result. + IF result_date + date_difference_interval <= date::TIMESTAMP THEN + result_date = result_date + date_difference_interval; + END IF; + RETURN result_date; + END IF; + END IF; +END; +$body$ +LANGUAGE plpgsql IMMUTABLE; + +create or replace view sys.all_objects as +select + name collate sys.database_default + , cast (object_id as integer) + , cast ( principal_id as integer) + , cast (schema_id as integer) + , cast (parent_object_id as integer) + , type collate sys.database_default + , cast (type_desc as sys.nvarchar(60)) + , cast (create_date as sys.datetime) + , cast (modify_date as sys.datetime) + , is_ms_shipped + , cast (is_published as sys.bit) + , cast (is_schema_published as sys.bit) +from +( +-- details of system tables +select + t.relname::sys.sysname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'U'::char(2) as type + , 'USER_TABLE' as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 1::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.table_types_internal tt on t.oid = tt.typrelid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'U' +where t.relpersistence in ('p', 'u', 't') +and t.relkind = 'r' +and (s.nspname = 'sys' or (nis.name is not null and ext.nspname is not null)) +and tt.typrelid is null +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') + +union all +-- details of user defined tables +select + t.relname::sys.sysname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'U'::char(2) as type + , 'USER_TABLE' as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.table_types_internal tt on t.oid = tt.typrelid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'U' +where t.relpersistence in ('p', 'u', 't') +and t.relkind = 'r' +and s.nspname <> 'sys' and nis.name is null +and ext.nspname is not null +and tt.typrelid is null +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') + +union all +-- details of system views +select + t.relname::sys.sysname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'V'::char(2) as type + , 'VIEW'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 1::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'V' +where t.relkind = 'v' +and (s.nspname = 'sys' or (nis.name is not null and ext.nspname is not null)) +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +union all +-- Details of user defined views + +-- Currently for pg_class, pg_proc UNIONs, we separated user defined objects and system objects because the +-- optimiser will be able to make a better estimation of number of rows(in case the query contains a filter on +-- is_ms_shipped column) and in turn chooses a better query plan. +select + t.relname::sys.sysname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'V'::char(2) as type + , 'VIEW'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = t.relname and nis.schemaid = s.oid and nis.type = 'V' +where t.relkind = 'v' +and s.nspname <> 'sys' and nis.name is null +and ext.nspname is not null +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +union all +-- details of user defined and system foreign key constraints +select + c.conname::sys.sysname as name + , c.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , c.conrelid as parent_object_id + , 'F'::char(2) as type + , 'FOREIGN_KEY_CONSTRAINT' + , null::timestamp as create_date + , null::timestamp as modify_date + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = c.conname and nis.schemaid = s.oid and nis.type = 'F' +where has_schema_privilege(s.oid, 'USAGE') +and c.contype = 'f' +and (s.nspname = 'sys' or ext.nspname is not null) +union all +-- details of user defined and system primary key constraints +select + c.conname::sys.sysname as name + , c.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , c.conrelid as parent_object_id + , 'PK'::char(2) as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = c.conname and nis.schemaid = s.oid and nis.type = 'PK' +where has_schema_privilege(s.oid, 'USAGE') +and c.contype = 'p' +and (s.nspname = 'sys' or ext.nspname is not null) +union all +-- details of system defined procedures +select + p.proname::sys.sysname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , cast (case when tr.tgrelid is not null + then tr.tgrelid + else 0 end as int) + as parent_object_id + , case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end as type + , case p.prokind + when 'p' then 'SQL_STORED_PROCEDURE'::varchar(60) + when 'a' then 'AGGREGATE_FUNCTION'::varchar(60) + else + case + when t.typname = 'trigger' + then 'SQL_TRIGGER'::varchar(60) + when p.proretset then + case + when t.typtype = 'c' + then 'SQL_TABLE_VALUED_FUNCTION'::varchar(60) + else 'SQL_INLINE_TABLE_VALUED_FUNCTION'::varchar(60) + end + else 'SQL_SCALAR_FUNCTION'::varchar(60) + end + end as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 1::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +inner join pg_catalog.pg_type t on t.oid = p.prorettype +left join pg_trigger tr on tr.tgfoid = p.oid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = p.proname and nis.schemaid = s.oid +and nis.type = (case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end) +where (s.nspname = 'sys' or (nis.name is not null and ext.nspname is not null)) +and has_schema_privilege(s.oid, 'USAGE') +and has_function_privilege(p.oid, 'EXECUTE') + +union all +-- details of user defined procedures +select + p.proname::sys.sysname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , cast (case when tr.tgrelid is not null + then tr.tgrelid + else 0 end as int) + as parent_object_id + , case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end as type + , case p.prokind + when 'p' then 'SQL_STORED_PROCEDURE'::varchar(60) + when 'a' then 'AGGREGATE_FUNCTION'::varchar(60) + else + case + when t.typname = 'trigger' + then 'SQL_TRIGGER'::varchar(60) + when p.proretset then + case + when t.typtype = 'c' + then 'SQL_TABLE_VALUED_FUNCTION'::varchar(60) + else 'SQL_INLINE_TABLE_VALUED_FUNCTION'::varchar(60) + end + else 'SQL_SCALAR_FUNCTION'::varchar(60) + end + end as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0::sys.bit as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +inner join pg_catalog.pg_type t on t.oid = p.prorettype +left join pg_trigger tr on tr.tgfoid = p.oid +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = p.proname and nis.schemaid = s.oid +and nis.type = (case p.prokind + when 'p' then 'P'::char(2) + when 'a' then 'AF'::char(2) + else + case + when t.typname = 'trigger' + then 'TR'::char(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::char(2) + else 'IF'::char(2) + end + else 'FN'::char(2) + end + end) +where s.nspname <> 'sys' and nis.name is null +and ext.nspname is not null +and has_schema_privilege(s.oid, 'USAGE') +and has_function_privilege(p.oid, 'EXECUTE') + +union all +-- details of all default constraints +select + ('DF_' || o.relname || '_' || d.oid)::sys.sysname as name + , d.oid as object_id + , null::int as principal_id + , o.relnamespace as schema_id + , d.adrelid as parent_object_id + , 'D'::char(2) as type + , 'DEFAULT_CONSTRAINT'::sys.nvarchar(60) AS type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_catalog.pg_attrdef d +inner join pg_attribute a on a.attrelid = d.adrelid and d.adnum = a.attnum +inner join pg_class o on d.adrelid = o.oid +inner join pg_namespace s on s.oid = o.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = ('DF_' || o.relname || '_' || d.oid) and nis.schemaid = s.oid and nis.type = 'D' +where a.atthasdef = 't' and a.attgenerated = '' +and (s.nspname = 'sys' or ext.nspname is not null) +and has_schema_privilege(s.oid, 'USAGE') +and has_column_privilege(a.attrelid, a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') +union all +-- details of all check constraints +select + c.conname::sys.sysname + , c.oid::integer as object_id + , NULL::integer as principal_id + , s.oid as schema_id + , c.conrelid::integer as parent_object_id + , 'C'::char(2) as type + , 'CHECK_CONSTRAINT'::sys.nvarchar(60) as type_desc + , null::sys.datetime as create_date + , null::sys.datetime as modify_date + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_catalog.pg_constraint as c +inner join pg_namespace s on s.oid = c.connamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = c.conname and nis.schemaid = s.oid and nis.type = 'C' +where has_schema_privilege(s.oid, 'USAGE') +and c.contype = 'c' and c.conrelid != 0 +and (s.nspname = 'sys' or ext.nspname is not null) +union all +-- details of user defined and system defined sequence objects +select + p.relname::sys.sysname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'SO'::char(2) as type + , 'SEQUENCE_OBJECT'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , CAST (case when (s.nspname = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class p +inner join pg_namespace s on s.oid = p.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join sys.shipped_objects_not_in_sys nis on nis.name = p.relname and nis.schemaid = s.oid and nis.type = 'SO' +where p.relkind = 'S' +and (s.nspname = 'sys' or ext.nspname is not null) +and has_schema_privilege(s.oid, 'USAGE') +union all +-- details of user defined table types +select + ('TT_' || tt.name || '_' || tt.type_table_object_id)::sys.sysname as name + , tt.type_table_object_id as object_id + , tt.principal_id as principal_id + , tt.schema_id as schema_id + , 0 as parent_object_id + , 'TT'::char(2) as type + , 'TABLE_TYPE'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , CAST (case when (tt.schema_id::regnamespace::text = 'sys' or nis.name is not null) then 1 + else 0 end as sys.bit ) as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from sys.table_types tt +left join sys.shipped_objects_not_in_sys nis on nis.name = ('TT_' || tt.name || '_' || tt.type_table_object_id)::name and nis.schemaid = tt.schema_id and nis.type = 'TT' +) ot; +GRANT SELECT ON sys.all_objects TO PUBLIC; + +CREATE OR REPLACE VIEW sys.server_principals +AS SELECT +CAST(Ext.orig_loginname AS sys.SYSNAME) AS name, +CAST(Base.oid As INT) AS principal_id, +CAST(CAST(Base.oid as INT) as sys.varbinary(85)) AS sid, +CAST(Ext.type AS CHAR(1)) as type, +CAST( + CASE + WHEN Ext.type = 'S' THEN 'SQL_LOGIN' + WHEN Ext.type = 'R' THEN 'SERVER_ROLE' + WHEN Ext.type = 'U' THEN 'WINDOWS_LOGIN' + ELSE NULL + END + AS NVARCHAR(60)) AS type_desc, +CAST(Ext.is_disabled AS INT) AS is_disabled, +CAST(Ext.create_date AS SYS.DATETIME) AS create_date, +CAST(Ext.modify_date AS SYS.DATETIME) AS modify_date, +CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.default_database_name END AS SYS.SYSNAME) AS default_database_name, +CAST(Ext.default_language_name AS SYS.SYSNAME) AS default_language_name, +CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.credential_id END AS INT) AS credential_id, +CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.owning_principal_id END AS INT) AS owning_principal_id, +CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.is_fixed_role END AS sys.BIT) AS is_fixed_role +FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname +WHERE pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER') +OR Ext.orig_loginname = suser_name() +OR Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default +OR Ext.type = 'R'; + +GRANT SELECT ON sys.server_principals TO PUBLIC; + +--SERVER_ROLE_MEMBER +CREATE OR REPLACE VIEW sys.server_role_members AS +SELECT +CAST(Authmbr.roleid AS INT) AS role_principal_id, +CAST(Authmbr.member AS INT) AS member_principal_id +FROM pg_catalog.pg_auth_members AS Authmbr +INNER JOIN pg_catalog.pg_roles AS Auth1 ON Auth1.oid = Authmbr.roleid +INNER JOIN pg_catalog.pg_roles AS Auth2 ON Auth2.oid = Authmbr.member +INNER JOIN sys.babelfish_authid_login_ext AS Ext1 ON Auth1.rolname = Ext1.rolname +INNER JOIN sys.babelfish_authid_login_ext AS Ext2 ON Auth2.rolname = Ext2.rolname +WHERE Ext1.type = 'R'; + +GRANT SELECT ON sys.server_role_members TO PUBLIC; + +create or replace view sys.schemas as +select + CAST(ext.orig_name as sys.SYSNAME) as name + , base.oid as schema_id + , base.nspowner as principal_id +from pg_catalog.pg_namespace base +inner join sys.babelfish_namespace_ext ext on base.nspname = ext.nspname +where ext.dbid = sys.db_id(); +GRANT SELECT ON sys.schemas TO PUBLIC; + +create or replace view sys.table_types_internal as +SELECT pt.typrelid + FROM pg_catalog.pg_type pt + INNER JOIN pg_catalog.pg_depend dep ON pt.typrelid = dep.objid + INNER JOIN pg_catalog.pg_class pc ON pc.oid = dep.objid + WHERE pt.typtype = 'c' AND dep.deptype = 'i' AND pc.relkind = 'r'; + +create or replace view sys.tables as +select + CAST(t.relname as sys._ci_sysname) as name + , CAST(t.oid as int) as object_id + , CAST(NULL as int) as principal_id + , CAST(t.relnamespace as int) as schema_id + , 0 as parent_object_id + , CAST('U' as CHAR(2)) as type + , CAST('USER_TABLE' as sys.nvarchar(60)) as type_desc + , CAST((select string_agg( + case + when option like 'bbf_rel_create_date=%%' then substring(option, 21) + else NULL + end, ',') + from unnest(t.reloptions) as option) + as sys.datetime) as create_date + , CAST((select string_agg( + case + when option like 'bbf_rel_create_date=%%' then substring(option, 21) + else NULL + end, ',') + from unnest(t.reloptions) as option) + as sys.datetime) as modify_date + , CAST(0 as sys.bit) as is_ms_shipped + , CAST(0 as sys.bit) as is_published + , CAST(0 as sys.bit) as is_schema_published + , case reltoastrelid when 0 then 0 else 1 end as lob_data_space_id + , CAST(NULL as int) as filestream_data_space_id + , CAST(relnatts as int) as max_column_id_used + , CAST(0 as sys.bit) as lock_on_bulk_load + , CAST(1 as sys.bit) as uses_ansi_nulls + , CAST(0 as sys.bit) as is_replicated + , CAST(0 as sys.bit) as has_replication_filter + , CAST(0 as sys.bit) as is_merge_published + , CAST(0 as sys.bit) as is_sync_tran_subscribed + , CAST(0 as sys.bit) as has_unchecked_assembly_data + , 0 as text_in_row_limit + , CAST(0 as sys.bit) as large_value_types_out_of_row + , CAST(0 as sys.bit) as is_tracked_by_cdc + , CAST(0 as sys.tinyint) as lock_escalation + , CAST('TABLE' as sys.nvarchar(60)) as lock_escalation_desc + , CAST(0 as sys.bit) as is_filetable + , CAST(0 as sys.tinyint) as durability + , CAST('SCHEMA_AND_DATA' as sys.nvarchar(60)) as durability_desc + , CAST(0 as sys.bit) is_memory_optimized + , case relpersistence when 't' then CAST(2 as sys.tinyint) else CAST(0 as sys.tinyint) end as temporal_type + , case relpersistence when 't' then CAST('SYSTEM_VERSIONED_TEMPORAL_TABLE' as sys.nvarchar(60)) else CAST('NON_TEMPORAL_TABLE' as sys.nvarchar(60)) end as temporal_type_desc + , CAST(null as integer) as history_table_id + , CAST(0 as sys.bit) as is_remote_data_archive_enabled + , CAST(0 as sys.bit) as is_external +from pg_class t +inner join sys.schemas sch on sch.schema_id = t.relnamespace +left join sys.table_types_internal tt on t.oid = tt.typrelid +where tt.typrelid is null +and t.relkind = 'r' +and has_schema_privilege(t.relnamespace, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER'); +GRANT SELECT ON sys.tables TO PUBLIC; + +create or replace view sys.all_columns as +select CAST(c.oid as int) as object_id + , CAST(a.attname as sys.sysname) as name + , CAST(a.attnum as int) as column_id + , CAST(t.oid as int) as system_type_id + , CAST(t.oid as int) as user_type_id + , CAST(sys.tsql_type_max_length_helper(coalesce(tsql_type_name, tsql_base_type_name), a.attlen, a.atttypmod) as smallint) as max_length + , CAST(case + when a.atttypmod != -1 then + sys.tsql_type_precision_helper(coalesce(tsql_type_name, tsql_base_type_name), a.atttypmod) + else + sys.tsql_type_precision_helper(coalesce(tsql_type_name, tsql_base_type_name), t.typtypmod) + end as sys.tinyint) as precision + , CAST(case + when a.atttypmod != -1 THEN + sys.tsql_type_scale_helper(coalesce(tsql_type_name, tsql_base_type_name), a.atttypmod, false) + else + sys.tsql_type_scale_helper(coalesce(tsql_type_name, tsql_base_type_name), t.typtypmod, false) + end as sys.tinyint) as scale + , CAST(coll.collname as sys.sysname) as collation_name + , case when a.attnotnull then CAST(0 as sys.bit) else CAST(1 as sys.bit) end as is_nullable + , CAST(0 as sys.bit) as is_ansi_padded + , CAST(0 as sys.bit) as is_rowguidcol + , CAST(case when a.attidentity <> ''::"char" then 1 else 0 end AS sys.bit) as is_identity + , CAST(case when a.attgenerated <> ''::"char" then 1 else 0 end AS sys.bit) as is_computed + , CAST(0 as sys.bit) as is_filestream + , CAST(0 as sys.bit) as is_replicated + , CAST(0 as sys.bit) as is_non_sql_subscribed + , CAST(0 as sys.bit) as is_merge_published + , CAST(0 as sys.bit) as is_dts_replicated + , CAST(0 as sys.bit) as is_xml_document + , CAST(0 as int) as xml_collection_id + , CAST(coalesce(d.oid, 0) as int) as default_object_id + , CAST(coalesce((select oid from pg_constraint where conrelid = t.oid and contype = 'c' and a.attnum = any(conkey) limit 1), 0) as int) as rule_object_id + , CAST(0 as sys.bit) as is_sparse + , CAST(0 as sys.bit) as is_column_set + , CAST(0 as sys.tinyint) as generated_always_type + , CAST('NOT_APPLICABLE' as sys.nvarchar(60)) as generated_always_type_desc +from pg_attribute a +inner join pg_class c on c.oid = a.attrelid +inner join pg_type t on t.oid = a.atttypid +inner join pg_namespace s on s.oid = c.relnamespace +left join sys.babelfish_namespace_ext ext on (s.nspname = ext.nspname and ext.dbid = sys.db_id()) +left join pg_attrdef d on c.oid = d.adrelid and a.attnum = d.adnum +left join pg_collation coll on coll.oid = a.attcollation +, sys.translate_pg_type_to_tsql(a.atttypid) AS tsql_type_name +, sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_base_type_name +where not a.attisdropped +and (s.nspname = 'sys' or ext.nspname is not null) +-- r = ordinary table, i = index, S = sequence, t = TOAST table, v = view, m = materialized view, c = composite type, f = foreign table, p = partitioned table +and c.relkind in ('r', 'v', 'm', 'f', 'p') +and has_schema_privilege(s.oid, 'USAGE') +and has_column_privilege(quote_ident(s.nspname) ||'.'||quote_ident(c.relname), a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') +and a.attnum > 0; +GRANT SELECT ON sys.all_columns TO PUBLIC; + +create or replace view sys.types As +-- For System types +select + tsql_type_name as name + , t.oid as system_type_id + , t.oid as user_type_id + , s.oid as schema_id + , cast(NULL as INT) as principal_id + , sys.tsql_type_max_length_helper(tsql_type_name, t.typlen, t.typtypmod, true) as max_length + , cast(sys.tsql_type_precision_helper(tsql_type_name, t.typtypmod) as int) as precision + , cast(sys.tsql_type_scale_helper(tsql_type_name, t.typtypmod, false) as int) as scale + , CASE c.collname + WHEN 'default' THEN default_collation_name + ELSE c.collname + END as collation_name + , case when typnotnull then 0 else 1 end as is_nullable + , 0 as is_user_defined + , 0 as is_assembly_type + , 0 as default_object_id + , 0 as rule_object_id + , 0 as is_table_type +from pg_type t +inner join pg_namespace s on s.oid = t.typnamespace +left join pg_collation c on c.oid = t.typcollation +, sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name +,cast(current_setting('babelfishpg_tsql.server_collation_name') as name) as default_collation_name +where +tsql_type_name IS NOT NULL +and pg_type_is_visible(t.oid) +and (s.nspname = 'pg_catalog' OR s.nspname = 'sys') +union all +-- For User Defined Types +select cast(t.typname as text) as name + , t.typbasetype as system_type_id + , t.oid as user_type_id + , t.typnamespace as schema_id + , null::integer as principal_id + , case when tt.typrelid is not null then -1::smallint else sys.tsql_type_max_length_helper(tsql_base_type_name, t.typlen, t.typtypmod) end as max_length + , case when tt.typrelid is not null then 0::smallint else cast(sys.tsql_type_precision_helper(tsql_base_type_name, t.typtypmod) as int) end as precision + , case when tt.typrelid is not null then 0::smallint else cast(sys.tsql_type_scale_helper(tsql_base_type_name, t.typtypmod, false) as int) end as scale + , CASE c.collname + WHEN 'default' THEN default_collation_name + ELSE c.collname + END as collation_name + , case when tt.typrelid is not null then 0 + else case when typnotnull then 0 else 1 end + end + as is_nullable + -- CREATE TYPE ... FROM is implemented as CREATE DOMAIN in babel + , 1 as is_user_defined + , 0 as is_assembly_type + , 0 as default_object_id + , 0 as rule_object_id + , case when tt.typrelid is not null then 1 else 0 end as is_table_type +from pg_type t +join sys.schemas sch on t.typnamespace = sch.schema_id +left join pg_collation c on c.oid = t.typcollation +left join sys.table_types_internal tt on t.typrelid = tt.typrelid +, sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name +, sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_base_type_name +, cast(current_setting('babelfishpg_tsql.server_collation_name') as name) as default_collation_name +-- we want to show details of user defined datatypes created under babelfish database +where + tsql_type_name IS NULL +and + ( + -- show all user defined datatypes created under babelfish database except table types + t.typtype = 'd' + or + -- only for table types + tt.typrelid is not null + ); +GRANT SELECT ON sys.types TO PUBLIC; + +CREATE OR REPLACE VIEW sys.sp_columns_100_view AS + SELECT + CAST(t4."TABLE_CATALOG" AS sys.sysname) AS TABLE_QUALIFIER, + CAST(t4."TABLE_SCHEMA" AS sys.sysname) AS TABLE_OWNER, + CAST(t4."TABLE_NAME" AS sys.sysname) AS TABLE_NAME, + CAST(t4."COLUMN_NAME" AS sys.sysname) AS COLUMN_NAME, + CAST(t5.data_type AS smallint) AS DATA_TYPE, + CAST(coalesce(tsql_type_name, t.typname) AS sys.sysname) AS TYPE_NAME, + + CASE WHEN t4."CHARACTER_MAXIMUM_LENGTH" = -1 THEN 0::INT + WHEN a.atttypmod != -1 + THEN + CAST(coalesce(t4."NUMERIC_PRECISION", t4."CHARACTER_MAXIMUM_LENGTH", sys.tsql_type_precision_helper(t4."DATA_TYPE", a.atttypmod)) AS INT) + WHEN tsql_type_name = 'timestamp' + THEN 8 + ELSE + CAST(coalesce(t4."NUMERIC_PRECISION", t4."CHARACTER_MAXIMUM_LENGTH", sys.tsql_type_precision_helper(t4."DATA_TYPE", t.typtypmod)) AS INT) + END AS PRECISION, + + CASE WHEN a.atttypmod != -1 + THEN + CAST(sys.tsql_type_length_for_sp_columns_helper(t4."DATA_TYPE", a.attlen, a.atttypmod) AS int) + ELSE + CAST(sys.tsql_type_length_for_sp_columns_helper(t4."DATA_TYPE", a.attlen, t.typtypmod) AS int) + END AS LENGTH, + + + CASE WHEN a.atttypmod != -1 + THEN + CAST(coalesce(t4."NUMERIC_SCALE", sys.tsql_type_scale_helper(t4."DATA_TYPE", a.atttypmod, true)) AS smallint) + ELSE + CAST(coalesce(t4."NUMERIC_SCALE", sys.tsql_type_scale_helper(t4."DATA_TYPE", t.typtypmod, true)) AS smallint) + END AS SCALE, + + + CAST(coalesce(t4."NUMERIC_PRECISION_RADIX", sys.tsql_type_radix_for_sp_columns_helper(t4."DATA_TYPE")) AS smallint) AS RADIX, + case + when t4."IS_NULLABLE" = 'YES' then CAST(1 AS smallint) + else CAST(0 AS smallint) + end AS NULLABLE, + + CAST(NULL AS varchar(254)) AS remarks, + CAST(t4."COLUMN_DEFAULT" AS sys.nvarchar(4000)) AS COLUMN_DEF, + CAST(t5.sql_data_type AS smallint) AS SQL_DATA_TYPE, + CAST(t5.SQL_DATETIME_SUB AS smallint) AS SQL_DATETIME_SUB, + + CASE WHEN t4."DATA_TYPE" = 'xml' THEN 0::INT + WHEN t4."DATA_TYPE" = 'sql_variant' THEN 8000::INT + WHEN t4."CHARACTER_MAXIMUM_LENGTH" = -1 THEN 0::INT + ELSE CAST(t4."CHARACTER_OCTET_LENGTH" AS int) + END AS CHAR_OCTET_LENGTH, + + CAST(t4."ORDINAL_POSITION" AS int) AS ORDINAL_POSITION, + CAST(t4."IS_NULLABLE" AS varchar(254)) AS IS_NULLABLE, + CAST(t5.ss_data_type AS sys.tinyint) AS SS_DATA_TYPE, + CAST(0 AS smallint) AS SS_IS_SPARSE, + CAST(0 AS smallint) AS SS_IS_COLUMN_SET, + CAST(t6.is_computed as smallint) AS SS_IS_COMPUTED, + CAST(t6.is_identity as smallint) AS SS_IS_IDENTITY, + CAST(NULL AS varchar(254)) SS_UDT_CATALOG_NAME, + CAST(NULL AS varchar(254)) SS_UDT_SCHEMA_NAME, + CAST(NULL AS varchar(254)) SS_UDT_ASSEMBLY_TYPE_NAME, + CAST(NULL AS varchar(254)) SS_XML_SCHEMACOLLECTION_CATALOG_NAME, + CAST(NULL AS varchar(254)) SS_XML_SCHEMACOLLECTION_SCHEMA_NAME, + CAST(NULL AS varchar(254)) SS_XML_SCHEMACOLLECTION_NAME + + FROM pg_catalog.pg_class t1 + JOIN sys.pg_namespace_ext t2 ON t1.relnamespace = t2.oid + JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on t2.nspname = ext.nspname + JOIN information_schema_tsql.columns t4 ON (t1.relname::sys.nvarchar(128) = t4."TABLE_NAME" AND ext.orig_name = t4."TABLE_SCHEMA") + LEFT JOIN pg_attribute a on a.attrelid = t1.oid AND a.attname::sys.nvarchar(128) = t4."COLUMN_NAME" + LEFT JOIN pg_type t ON t.oid = a.atttypid + LEFT JOIN sys.columns t6 ON + ( + t1.oid = t6.object_id AND + t4."ORDINAL_POSITION" = t6.column_id + ) + , sys.translate_pg_type_to_tsql(a.atttypid) AS tsql_type_name + , sys.spt_datatype_info_table AS t5 + WHERE (t4."DATA_TYPE" = CAST(t5.TYPE_NAME AS sys.nvarchar(128)) OR (t4."DATA_TYPE" = 'bytea' AND t5.TYPE_NAME = 'image')) + AND ext.dbid = sys.db_id(); +GRANT SELECT on sys.sp_columns_100_view TO PUBLIC; + + +CREATE OR REPLACE VIEW sys.sp_pkeys_view AS +SELECT +CAST(t4."TABLE_CATALOG" AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t4."TABLE_SCHEMA" AS sys.sysname) AS TABLE_OWNER, +CAST(t1.relname AS sys.sysname) AS TABLE_NAME, +CAST(t4."COLUMN_NAME" AS sys.sysname) AS COLUMN_NAME, +CAST(seq AS smallint) AS KEY_SEQ, +CAST(t5.conname AS sys.sysname) AS PK_NAME +FROM pg_catalog.pg_class t1 + JOIN sys.pg_namespace_ext t2 ON t1.relnamespace = t2.oid + JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on t2.nspname = ext.nspname + JOIN information_schema_tsql.columns t4 ON (t1.relname = t4."TABLE_NAME" COLLATE sys.database_default AND ext.orig_name = t4."TABLE_SCHEMA" ) + JOIN pg_constraint t5 ON t1.oid = t5.conrelid + , generate_series(1,16) seq -- SQL server has max 16 columns per primary key +WHERE t5.contype = 'p' + AND CAST(t4."ORDINAL_POSITION" AS smallint) = ANY (t5.conkey) + AND CAST(t4."ORDINAL_POSITION" AS smallint) = t5.conkey[seq] + AND ext.dbid = sys.db_id(); + +GRANT SELECT on sys.sp_pkeys_view TO PUBLIC; + +CREATE OR REPLACE VIEW sys.sp_statistics_view AS +SELECT +CAST(t3."TABLE_CATALOG" AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t3."TABLE_SCHEMA" AS sys.sysname) AS TABLE_OWNER, +CAST(t3."TABLE_NAME" AS sys.sysname) AS TABLE_NAME, +CAST(NULL AS smallint) AS NON_UNIQUE, +CAST(NULL AS sys.sysname) AS INDEX_QUALIFIER, +CAST(NULL AS sys.sysname) AS INDEX_NAME, +CAST(0 AS smallint) AS TYPE, +CAST(NULL AS smallint) AS SEQ_IN_INDEX, +CAST(NULL AS sys.sysname) AS COLUMN_NAME, +CAST(NULL AS sys.varchar(1)) AS COLLATION, +CAST(t1.reltuples AS int) AS CARDINALITY, +CAST(t1.relpages AS int) AS PAGES, +CAST(NULL AS sys.varchar(128)) AS FILTER_CONDITION +FROM pg_catalog.pg_class t1 + JOIN sys.schemas s1 ON s1.schema_id = t1.relnamespace + JOIN information_schema_tsql.columns t3 ON (lower(t1.relname) = lower(t3."TABLE_NAME") COLLATE C AND s1.name = t3."TABLE_SCHEMA") + , generate_series(0,31) seq -- SQL server has max 32 columns per index +UNION +SELECT +CAST(t4."TABLE_CATALOG" AS sys.sysname) AS TABLE_QUALIFIER, +CAST(t4."TABLE_SCHEMA" AS sys.sysname) AS TABLE_OWNER, +CAST(t4."TABLE_NAME" AS sys.sysname) AS TABLE_NAME, +CASE +WHEN t5.indisunique = 't' THEN CAST(0 AS smallint) +ELSE CAST(1 AS smallint) +END AS NON_UNIQUE, +CAST(t1.relname AS sys.sysname) AS INDEX_QUALIFIER, +-- the index name created by CREATE INDEX is re-mapped, find it (by checking +-- the ones not in pg_constraint) and restoring it back before display +CASE +WHEN t8.oid > 0 THEN CAST(t6.relname AS sys.sysname) +ELSE CAST(SUBSTRING(t6.relname,1,LENGTH(t6.relname)-32-LENGTH(t1.relname)) AS sys.sysname) +END AS INDEX_NAME, +CASE +WHEN t5.indisclustered = 't' THEN CAST(1 AS smallint) +ELSE CAST(3 AS smallint) +END AS TYPE, +CAST(seq + 1 AS smallint) AS SEQ_IN_INDEX, +CAST(t4."COLUMN_NAME" AS sys.sysname) AS COLUMN_NAME, +CAST('A' AS sys.varchar(1)) AS COLLATION, +CAST(t7.n_distinct AS int) AS CARDINALITY, +CAST(0 AS int) AS PAGES, --not supported +CAST(NULL AS sys.varchar(128)) AS FILTER_CONDITION +FROM pg_catalog.pg_class t1 + JOIN sys.schemas s1 ON s1.schema_id = t1.relnamespace + JOIN pg_catalog.pg_roles t3 ON t1.relowner = t3.oid + JOIN information_schema_tsql.columns t4 ON (lower(t1.relname) = lower(t4."TABLE_NAME") COLLATE C AND s1.name = t4."TABLE_SCHEMA") + JOIN (pg_catalog.pg_index t5 JOIN + pg_catalog.pg_class t6 ON t5.indexrelid = t6.oid) ON t1.oid = t5.indrelid + JOIN pg_catalog.pg_namespace nsp ON (t1.relnamespace = nsp.oid) + LEFT JOIN pg_catalog.pg_stats t7 ON (t1.relname = t7.tablename AND t7.schemaname = nsp.nspname) + LEFT JOIN pg_catalog.pg_constraint t8 ON t5.indexrelid = t8.conindid + , generate_series(0,31) seq -- SQL server has max 32 columns per index +WHERE CAST(t4."ORDINAL_POSITION" AS smallint) = ANY (t5.indkey) + AND CAST(t4."ORDINAL_POSITION" AS smallint) = t5.indkey[seq]; +GRANT SELECT on sys.sp_statistics_view 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 + 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 = '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; + 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 + -- 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 = sys.db_id() 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 + 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; + +CREATE OR REPLACE VIEW information_schema_tsql.columns AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(c.relname AS sys.nvarchar(128)) AS "TABLE_NAME", + CAST(a.attname AS sys.nvarchar(128)) AS "COLUMN_NAME", + CAST(a.attnum AS int) AS "ORDINAL_POSITION", + CAST(CASE WHEN a.attgenerated = '' THEN pg_get_expr(ad.adbin, ad.adrelid) END AS sys.nvarchar(4000)) AS "COLUMN_DEFAULT", + CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END + AS varchar(3)) + AS "IS_NULLABLE", + + CAST( + CASE WHEN tsql_type_name = 'sysname' THEN sys.translate_pg_type_to_tsql(t.typbasetype) + WHEN tsql_type_name.tsql_type_name IS NULL THEN format_type(t.oid, NULL::integer) + ELSE tsql_type_name END + AS sys.nvarchar(128)) + AS "DATA_TYPE", + + CAST( + information_schema_tsql._pgtsql_char_max_length(tsql_type_name, true_typmod) + AS int) + AS "CHARACTER_MAXIMUM_LENGTH", + + CAST( + information_schema_tsql._pgtsql_char_octet_length(tsql_type_name, true_typmod) + AS int) + AS "CHARACTER_OCTET_LENGTH", + + CAST( + /* Handle Tinyint separately */ + information_schema_tsql._pgtsql_numeric_precision(tsql_type_name, true_typid, true_typmod) + AS sys.tinyint) + AS "NUMERIC_PRECISION", + + CAST( + information_schema_tsql._pgtsql_numeric_precision_radix(tsql_type_name, true_typid, true_typmod) + AS smallint) + AS "NUMERIC_PRECISION_RADIX", + + CAST( + information_schema_tsql._pgtsql_numeric_scale(tsql_type_name, true_typid, true_typmod) + AS int) + AS "NUMERIC_SCALE", + + CAST( + information_schema_tsql._pgtsql_datetime_precision(tsql_type_name, true_typmod) + AS smallint) + AS "DATETIME_PRECISION", + + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_CATALOG", + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_SCHEMA", + /* + * TODO: We need to first create mapping of collation name to char-set name; + * Until then return null. + */ + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_NAME", + + CAST(NULL as sys.nvarchar(128)) AS "COLLATION_CATALOG", + CAST(NULL as sys.nvarchar(128)) AS "COLLATION_SCHEMA", + + /* Returns Babelfish specific collation name. */ + CAST(co.collname AS sys.nvarchar(128)) AS "COLLATION_NAME", + + CAST(CASE WHEN t.typtype = 'd' AND nt.nspname <> 'pg_catalog' AND nt.nspname <> 'sys' + THEN nc.dbname ELSE null END + AS sys.nvarchar(128)) AS "DOMAIN_CATALOG", + CAST(CASE WHEN t.typtype = 'd' AND nt.nspname <> 'pg_catalog' AND nt.nspname <> 'sys' + THEN ext.orig_name ELSE null END + AS sys.nvarchar(128)) AS "DOMAIN_SCHEMA", + CAST(CASE WHEN t.typtype = 'd' AND nt.nspname <> 'pg_catalog' AND nt.nspname <> 'sys' + THEN t.typname ELSE null END + AS sys.nvarchar(128)) AS "DOMAIN_NAME" + + FROM (pg_attribute a LEFT JOIN pg_attrdef ad ON attrelid = adrelid AND attnum = adnum) + JOIN (pg_class c JOIN sys.pg_namespace_ext nc ON (c.relnamespace = nc.oid)) ON a.attrelid = c.oid + JOIN (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid)) ON a.atttypid = t.oid + LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON (bt.typnamespace = nbt.oid)) + ON (t.typtype = 'd' AND t.typbasetype = bt.oid) + LEFT JOIN pg_collation co on co.oid = a.attcollation + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname, + information_schema_tsql._pgtsql_truetypid(nt, a, t) AS true_typid, + information_schema_tsql._pgtsql_truetypmod(nt, a, t) AS true_typmod, + sys.translate_pg_type_to_tsql(true_typid) AS tsql_type_name + + WHERE (NOT pg_is_other_temp_schema(nc.oid)) + AND a.attnum > 0 AND NOT a.attisdropped + AND c.relkind IN ('r', 'v', 'p') + AND (pg_has_role(c.relowner, 'USAGE') + OR has_column_privilege(c.oid, a.attnum, + 'SELECT, INSERT, UPDATE, REFERENCES')) + AND ext.dbid =sys.db_id(); + +GRANT SELECT ON information_schema_tsql.columns TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.domains AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "DOMAIN_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "DOMAIN_SCHEMA", + CAST(t.typname AS sys.sysname) AS "DOMAIN_NAME", + CAST(case when is_tbl_type THEN 'table type' ELSE tsql_type_name END AS sys.sysname) AS "DATA_TYPE", + + CAST(information_schema_tsql._pgtsql_char_max_length(tsql_type_name, t.typtypmod) + AS int) + AS "CHARACTER_MAXIMUM_LENGTH", + + CAST(information_schema_tsql._pgtsql_char_octet_length(tsql_type_name, t.typtypmod) + AS int) + AS "CHARACTER_OCTET_LENGTH", + + CAST(NULL as sys.nvarchar(128)) AS "COLLATION_CATALOG", + CAST(NULL as sys.nvarchar(128)) AS "COLLATION_SCHEMA", + + /* Returns Babelfish specific collation name. */ + CAST( + CASE co.collname + WHEN 'default' THEN current_setting('babelfishpg_tsql.server_collation_name') + ELSE co.collname + END + AS sys.nvarchar(128)) AS "COLLATION_NAME", + + CAST(null AS sys.varchar(6)) AS "CHARACTER_SET_CATALOG", + CAST(null AS sys.varchar(3)) AS "CHARACTER_SET_SCHEMA", + /* + * TODO: We need to first create mapping of collation name to char-set name; + * Until then return null. + */ + CAST(null AS sys.nvarchar(128)) AS "CHARACTER_SET_NAME", + + CAST(information_schema_tsql._pgtsql_numeric_precision(tsql_type_name, t.typbasetype, t.typtypmod) + AS sys.tinyint) + AS "NUMERIC_PRECISION", + + CAST(information_schema_tsql._pgtsql_numeric_precision_radix(tsql_type_name, t.typbasetype, t.typtypmod) + AS smallint) + AS "NUMERIC_PRECISION_RADIX", + + CAST(information_schema_tsql._pgtsql_numeric_scale(tsql_type_name, t.typbasetype, t.typtypmod) + AS int) + AS "NUMERIC_SCALE", + + CAST(information_schema_tsql._pgtsql_datetime_precision(tsql_type_name, t.typtypmod) + AS smallint) + AS "DATETIME_PRECISION", + + CAST(case when is_tbl_type THEN NULL ELSE t.typdefault END AS sys.nvarchar(4000)) AS "DOMAIN_DEFAULT" + + FROM (pg_type t JOIN sys.pg_namespace_ext nc ON t.typnamespace = nc.oid) + LEFT JOIN pg_collation co ON t.typcollation = co.oid + LEFT JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname, + sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_type_name, + sys.is_table_type(t.typrelid) as is_tbl_type + + WHERE (pg_has_role(t.typowner, 'USAGE') + OR has_type_privilege(t.oid, 'USAGE')) + AND (t.typtype = 'd' OR is_tbl_type) + AND ext.dbid = sys.db_id(); + +GRANT SELECT ON information_schema_tsql.domains TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.tables AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST( + CASE WHEN c.reloptions[1] LIKE 'bbf_original_rel_name%' THEN substring(c.reloptions[1], 23) + ELSE c.relname END + AS sys._ci_sysname) AS "TABLE_NAME", + + CAST( + CASE WHEN c.relkind IN ('r', 'p') THEN 'BASE TABLE' + WHEN c.relkind = 'v' THEN 'VIEW' + ELSE null END + AS sys.varchar(10)) COLLATE sys.database_default AS "TABLE_TYPE" + + FROM sys.pg_namespace_ext nc JOIN pg_class c ON (nc.oid = c.relnamespace) + LEFT OUTER JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname + + WHERE c.relkind IN ('r', 'v', 'p') + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) + AND ext.dbid = sys.db_id() + AND (NOT c.relname = 'sysdatabases'); + +GRANT SELECT ON information_schema_tsql.tables TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.table_constraints AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG", + CAST(extc.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA", + CAST(c.conname AS sys.sysname) AS "CONSTRAINT_NAME", + CAST(nr.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(extr.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(r.relname AS sys.sysname) AS "TABLE_NAME", + CAST( + CASE c.contype WHEN 'c' THEN 'CHECK' + WHEN 'f' THEN 'FOREIGN KEY' + WHEN 'p' THEN 'PRIMARY KEY' + WHEN 'u' THEN 'UNIQUE' END + AS sys.varchar(11)) COLLATE sys.database_default AS "CONSTRAINT_TYPE", + CAST('NO' AS sys.varchar(2)) AS "IS_DEFERRABLE", + CAST('NO' AS sys.varchar(2)) AS "INITIALLY_DEFERRED" + + FROM sys.pg_namespace_ext nc LEFT OUTER JOIN sys.babelfish_namespace_ext extc ON nc.nspname = extc.nspname, + sys.pg_namespace_ext nr LEFT OUTER JOIN sys.babelfish_namespace_ext extr ON nr.nspname = extr.nspname, + pg_constraint c, + pg_class r + + WHERE nc.oid = c.connamespace AND nr.oid = r.relnamespace + AND c.conrelid = r.oid + AND c.contype NOT IN ('t', 'x') + AND r.relkind IN ('r', 'p') + AND (NOT pg_is_other_temp_schema(nr.oid)) + AND (pg_has_role(r.relowner, 'USAGE') + OR has_table_privilege(r.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(r.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) + AND extc.dbid = sys.db_id(); + +GRANT SELECT ON information_schema_tsql.table_constraints TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.views AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(c.relname AS sys.nvarchar(128)) AS "TABLE_NAME", + CAST(vd.definition AS sys.nvarchar(4000)) AS "VIEW_DEFINITION", + + CAST( + CASE WHEN 'check_option=cascaded' = ANY (c.reloptions) + THEN 'CASCADE' + ELSE 'NONE' END + AS sys.varchar(7)) COLLATE sys.database_default AS "CHECK_OPTION", + + CAST('NO' AS sys.varchar(2)) AS "IS_UPDATABLE" + + FROM sys.pg_namespace_ext nc JOIN pg_class c ON (nc.oid = c.relnamespace) + LEFT OUTER JOIN sys.babelfish_namespace_ext ext + ON (nc.nspname = ext.nspname COLLATE sys.database_default) + LEFT OUTER JOIN sys.babelfish_view_def vd + ON ext.dbid = vd.dbid + AND (ext.orig_name = vd.schema_name COLLATE sys.database_default) + AND (CAST(c.relname AS sys.nvarchar(128)) = vd.object_name COLLATE sys.database_default) + + WHERE c.relkind = 'v' + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(c.relowner, 'USAGE') + OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) + AND ext.dbid = sys.db_id(); + +GRANT SELECT ON information_schema_tsql.views TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.check_constraints AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG", + CAST(extc.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA", + CAST(c.conname AS sys.sysname) AS "CONSTRAINT_NAME", + CAST(sys.tsql_get_constraintdef(c.oid) AS sys.nvarchar(4000)) AS "CHECK_CLAUSE" + + FROM sys.pg_namespace_ext nc LEFT OUTER JOIN sys.babelfish_namespace_ext extc ON nc.nspname = extc.nspname, + pg_constraint c, + pg_class r + + WHERE nc.oid = c.connamespace AND nc.oid = r.relnamespace + AND c.conrelid = r.oid + AND c.contype = 'c' + AND r.relkind IN ('r', 'p') + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(r.relowner, 'USAGE') + OR has_table_privilege(r.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER') + OR has_any_column_privilege(r.oid, 'SELECT, INSERT, UPDATE, REFERENCES')) + AND extc.dbid = sys.db_id(); + +GRANT SELECT ON information_schema_tsql.check_constraints TO PUBLIC; + + +CREATE OR REPLACE VIEW information_schema_tsql.routines AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "SPECIFIC_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "SPECIFIC_SCHEMA", + CAST(p.proname AS sys.nvarchar(128)) AS "SPECIFIC_NAME", + CAST(nc.dbname AS sys.nvarchar(128)) AS "ROUTINE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "ROUTINE_SCHEMA", + CAST(p.proname AS sys.nvarchar(128)) AS "ROUTINE_NAME", + CAST(CASE p.prokind WHEN 'f' THEN 'FUNCTION' WHEN 'p' THEN 'PROCEDURE' END + AS sys.nvarchar(20)) AS "ROUTINE_TYPE", + CAST(NULL AS sys.nvarchar(128)) AS "MODULE_CATALOG", + CAST(NULL AS sys.nvarchar(128)) AS "MODULE_SCHEMA", + CAST(NULL AS sys.nvarchar(128)) AS "MODULE_NAME", + CAST(NULL AS sys.nvarchar(128)) AS "UDT_CATALOG", + CAST(NULL AS sys.nvarchar(128)) AS "UDT_SCHEMA", + CAST(NULL AS sys.nvarchar(128)) AS "UDT_NAME", + CAST(case when is_tbl_type THEN 'table' when p.prokind = 'p' THEN NULL ELSE tsql_type_name END AS sys.nvarchar(128)) AS "DATA_TYPE", + CAST(information_schema_tsql._pgtsql_char_max_length_for_routines(tsql_type_name, true_typmod) + AS int) + AS "CHARACTER_MAXIMUM_LENGTH", + CAST(information_schema_tsql._pgtsql_char_octet_length_for_routines(tsql_type_name, true_typmod) + AS int) + AS "CHARACTER_OCTET_LENGTH", + CAST(NULL AS sys.nvarchar(128)) AS "COLLATION_CATALOG", + CAST(NULL AS sys.nvarchar(128)) AS "COLLATION_SCHEMA", + CAST( + CASE co.collname + WHEN 'default' THEN current_setting('babelfishpg_tsql.server_collation_name') + ELSE co.collname + END + AS sys.nvarchar(128)) AS "COLLATION_NAME", + CAST(NULL AS sys.nvarchar(128)) AS "CHARACTER_SET_CATALOG", + CAST(NULL AS sys.nvarchar(128)) AS "CHARACTER_SET_SCHEMA", + /* + * TODO: We need to first create mapping of collation name to char-set name; + * Until then return null. + */ + CAST(case when tsql_type_name IN ('nchar','nvarchar') THEN 'UNICODE' when tsql_type_name IN ('char','varchar') THEN 'iso_1' ELSE NULL END AS sys.nvarchar(128)) AS "CHARACTER_SET_NAME", + CAST(information_schema_tsql._pgtsql_numeric_precision(tsql_type_name, t.oid, true_typmod) + AS smallint) + AS "NUMERIC_PRECISION", + CAST(information_schema_tsql._pgtsql_numeric_precision_radix(tsql_type_name, case when t.typtype = 'd' THEN t.typbasetype ELSE t.oid END, true_typmod) + AS smallint) + AS "NUMERIC_PRECISION_RADIX", + CAST(information_schema_tsql._pgtsql_numeric_scale(tsql_type_name, t.oid, true_typmod) + AS smallint) + AS "NUMERIC_SCALE", + CAST(information_schema_tsql._pgtsql_datetime_precision(tsql_type_name, true_typmod) + AS smallint) + AS "DATETIME_PRECISION", + CAST(NULL AS sys.nvarchar(30)) AS "INTERVAL_TYPE", + CAST(NULL AS smallint) AS "INTERVAL_PRECISION", + CAST(NULL AS sys.nvarchar(128)) AS "TYPE_UDT_CATALOG", + CAST(NULL AS sys.nvarchar(128)) AS "TYPE_UDT_SCHEMA", + CAST(NULL AS sys.nvarchar(128)) AS "TYPE_UDT_NAME", + CAST(NULL AS sys.nvarchar(128)) AS "SCOPE_CATALOG", + CAST(NULL AS sys.nvarchar(128)) AS "SCOPE_SCHEMA", + CAST(NULL AS sys.nvarchar(128)) AS "SCOPE_NAME", + CAST(NULL AS bigint) AS "MAXIMUM_CARDINALITY", + CAST(NULL AS sys.nvarchar(128)) AS "DTD_IDENTIFIER", + CAST(CASE WHEN l.lanname = 'sql' THEN 'SQL' WHEN l.lanname = 'pltsql' THEN 'SQL' ELSE 'EXTERNAL' END AS sys.nvarchar(30)) AS "ROUTINE_BODY", + CAST(f.definition AS sys.nvarchar(4000)) AS "ROUTINE_DEFINITION", + CAST(NULL AS sys.nvarchar(128)) AS "EXTERNAL_NAME", + CAST(NULL AS sys.nvarchar(30)) AS "EXTERNAL_LANGUAGE", + CAST(NULL AS sys.nvarchar(30)) AS "PARAMETER_STYLE", + CAST(CASE WHEN p.provolatile = 'i' THEN 'YES' ELSE 'NO' END AS sys.nvarchar(10)) AS "IS_DETERMINISTIC", + CAST(CASE p.prokind WHEN 'p' THEN 'MODIFIES' ELSE 'READS' END AS sys.nvarchar(30)) AS "SQL_DATA_ACCESS", + CAST(CASE WHEN p.prokind <> 'p' THEN + CASE WHEN p.proisstrict THEN 'YES' ELSE 'NO' END END AS sys.nvarchar(10)) AS "IS_NULL_CALL", + CAST(NULL AS sys.nvarchar(128)) AS "SQL_PATH", + CAST('YES' AS sys.nvarchar(10)) AS "SCHEMA_LEVEL_ROUTINE", + CAST(CASE p.prokind WHEN 'f' THEN 0 WHEN 'p' THEN -1 END AS smallint) AS "MAX_DYNAMIC_RESULT_SETS", + CAST('NO' AS sys.nvarchar(10)) AS "IS_USER_DEFINED_CAST", + CAST('NO' AS sys.nvarchar(10)) AS "IS_IMPLICITLY_INVOCABLE", + CAST(NULL AS sys.datetime) AS "CREATED", + CAST(NULL AS sys.datetime) AS "LAST_ALTERED" + + FROM sys.pg_namespace_ext nc LEFT JOIN sys.babelfish_namespace_ext ext ON nc.nspname = ext.nspname, + pg_proc p inner join sys.schemas sch on sch.schema_id = p.pronamespace + inner join sys.all_objects ao on ao.object_id = CAST(p.oid AS INT) + LEFT JOIN sys.babelfish_function_ext f ON p.proname = f.funcname AND sch.schema_id::regnamespace::name = f.nspname + AND sys.babelfish_get_pltsql_function_signature(p.oid) = f.funcsignature COLLATE "C", + pg_language l, + pg_type t LEFT JOIN pg_collation co ON t.typcollation = co.oid, + sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name, + sys.tsql_get_returnTypmodValue(p.oid) AS true_typmod, + sys.is_table_type(t.typrelid) as is_tbl_type + + WHERE + (case p.prokind + when 'p' then true + when 'a' then false + else + (case format_type(p.prorettype, null) + when 'trigger' then false + else true + end) + end) + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND has_function_privilege(p.oid, 'EXECUTE') + AND (pg_has_role(t.typowner, 'USAGE') + OR has_type_privilege(t.oid, 'USAGE')) + AND ext.dbid = sys.db_id() + AND p.prolang = l.oid + AND p.prorettype = t.oid + AND p.pronamespace = nc.oid + AND CAST(ao.is_ms_shipped as INT) = 0; + +GRANT SELECT ON information_schema_tsql.routines TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.SEQUENCES AS + SELECT CAST(nc.dbname AS sys.nvarchar(128)) AS "SEQUENCE_CATALOG", + CAST(extc.orig_name AS sys.nvarchar(128)) AS "SEQUENCE_SCHEMA", + CAST(r.relname AS sys.nvarchar(128)) AS "SEQUENCE_NAME", + CAST(CASE WHEN tsql_type_name = 'sysname' THEN sys.translate_pg_type_to_tsql(t.typbasetype) ELSE tsql_type_name END + AS sys.nvarchar(128))AS "DATA_TYPE", -- numeric and decimal data types are converted into bigint which is due to Postgres inherent implementation + CAST(information_schema_tsql._pgtsql_numeric_precision(tsql_type_name, t.oid, -1) + AS smallint) AS "NUMERIC_PRECISION", + CAST(information_schema_tsql._pgtsql_numeric_precision_radix(tsql_type_name, case when t.typtype = 'd' THEN t.typbasetype ELSE t.oid END, -1) + AS smallint) AS "NUMERIC_PRECISION_RADIX", + CAST(information_schema_tsql._pgtsql_numeric_scale(tsql_type_name, t.oid, -1) + AS int) AS "NUMERIC_SCALE", + CAST(s.seqstart AS sys.sql_variant) AS "START_VALUE", + CAST(s.seqmin AS sys.sql_variant) AS "MINIMUM_VALUE", + CAST(s.seqmax AS sys.sql_variant) AS "MAXIMUM_VALUE", + CAST(s.seqincrement AS sys.sql_variant) AS "INCREMENT", + CAST( CASE WHEN s.seqcycle = 't' THEN 1 ELSE 0 END AS int) AS "CYCLE_OPTION", + CAST(NULL AS sys.nvarchar(128)) AS "DECLARED_DATA_TYPE", + CAST(NULL AS int) AS "DECLARED_NUMERIC_PRECISION", + CAST(NULL AS int) AS "DECLARED_NUMERIC_SCALE" + FROM sys.pg_namespace_ext nc JOIN sys.babelfish_namespace_ext extc ON nc.nspname = extc.nspname, + pg_sequence s join pg_class r on s.seqrelid = r.oid join pg_type t on s.seqtypid=t.oid, + sys.translate_pg_type_to_tsql(s.seqtypid) AS tsql_type_name + WHERE nc.oid = r.relnamespace + AND extc.dbid = sys.db_id() + AND r.relkind = 'S' + AND (NOT pg_is_other_temp_schema(nc.oid)) + AND (pg_has_role(r.relowner, 'USAGE') + OR has_sequence_privilege(r.oid, 'SELECT, UPDATE, USAGE')); + +GRANT SELECT ON information_schema_tsql.sequences TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.key_column_usage AS + SELECT + CAST(nc.dbname AS sys.nvarchar(128)) AS "CONSTRAINT_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "CONSTRAINT_SCHEMA", + CAST(c.conname AS sys.nvarchar(128)) AS "CONSTRAINT_NAME", + CAST(nc.dbname AS sys.nvarchar(128)) AS "TABLE_CATALOG", + CAST(ext.orig_name AS sys.nvarchar(128)) AS "TABLE_SCHEMA", + CAST(r.relname AS sys.nvarchar(128)) AS "TABLE_NAME", + CAST(a.attname AS sys.nvarchar(128)) AS "COLUMN_NAME", + CAST(ord AS int) AS "ORDINAL_POSITION" + FROM + pg_constraint c + JOIN pg_class r ON r.oid = c.conrelid AND c.contype in ('p','u','f') AND r.relkind in ('r','p') + JOIN sys.pg_namespace_ext nc ON nc.oid = c.connamespace AND r.relnamespace = nc.oid + JOIN sys.babelfish_namespace_ext ext ON ext.nspname = nc.nspname AND ext.dbid = sys.db_id() + CROSS JOIN unnest(c.conkey) WITH ORDINALITY AS ak(j,ord) + LEFT JOIN pg_attribute a ON a.attrelid = r.oid AND a.attnum = ak.j + WHERE + pg_has_role(r.relowner, 'USAGE'::text) + OR has_column_privilege(r.oid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text) + AND NOT pg_is_other_temp_schema(nc.oid) + ; +GRANT SELECT ON information_schema_tsql.key_column_usage TO PUBLIC; + +CREATE OR REPLACE VIEW information_schema_tsql.schemata AS + SELECT CAST(sys.db_name() AS sys.sysname) AS "CATALOG_NAME", + CAST(CASE WHEN np.nspname LIKE CONCAT(sys.db_name(),'%') THEN RIGHT(np.nspname, LENGTH(np.nspname) - LENGTH(sys.db_name()) - 1) + ELSE np.nspname END AS sys.nvarchar(128)) AS "SCHEMA_NAME", + -- For system-defined schemas, schema-owner name will be same as schema_name + -- For user-defined schemas having default owner, schema-owner will be dbo + -- For user-defined schemas with explicit owners, rolname contains dbname followed + -- by owner name, so need to extract the owner name from rolname always. + CAST(CASE WHEN sys.bbf_is_shared_schema(np.nspname) = TRUE THEN np.nspname + WHEN r.rolname LIKE CONCAT(sys.db_name(),'%') THEN + CASE WHEN RIGHT(r.rolname, LENGTH(r.rolname) - LENGTH(sys.db_name()) - 1) = 'db_owner' THEN 'dbo' + ELSE RIGHT(r.rolname, LENGTH(r.rolname) - LENGTH(sys.db_name()) - 1) END ELSE 'dbo' END + AS sys.nvarchar(128)) AS "SCHEMA_OWNER", + CAST(null AS sys.varchar(6)) AS "DEFAULT_CHARACTER_SET_CATALOG", + CAST(null AS sys.varchar(3)) AS "DEFAULT_CHARACTER_SET_SCHEMA", + -- TODO: We need to first create mapping of collation name to char-set name; + -- Until then return null for DEFAULT_CHARACTER_SET_NAME + CAST(null AS sys.sysname) AS "DEFAULT_CHARACTER_SET_NAME" + FROM ((pg_catalog.pg_namespace np LEFT JOIN sys.pg_namespace_ext nc on np.nspname = nc.nspname) + LEFT JOIN pg_catalog.pg_roles r on r.oid = nc.nspowner) LEFT JOIN sys.babelfish_namespace_ext ext on nc.nspname = ext.nspname + WHERE (ext.dbid = sys.db_id() OR np.nspname in ('sys', 'information_schema_tsql')) AND + (pg_has_role(np.nspowner, 'USAGE') OR has_schema_privilege(np.oid, 'CREATE, USAGE')) + ORDER BY nc.nspname, np.nspname; + +GRANT SELECT ON information_schema_tsql.schemata TO PUBLIC; + + +CREATE OR REPLACE FUNCTION sys.has_perms_by_name( + securable SYS.SYSNAME, + securable_class SYS.NVARCHAR(60), + permission SYS.SYSNAME, + sub_securable SYS.SYSNAME DEFAULT NULL, + sub_securable_class SYS.NVARCHAR(60) DEFAULT NULL +) +RETURNS integer +LANGUAGE plpgsql +STABLE +AS $$ +DECLARE + db_name text COLLATE sys.database_default; + bbf_schema_name text; + pg_schema text COLLATE sys.database_default; + implied_dbo_permissions boolean; + fully_supported boolean; + is_cross_db boolean := false; + object_name text COLLATE sys.database_default; + database_id smallint; + namespace_id oid; + userid oid; + object_type text; + function_signature text; + qualified_name text; + return_value integer; + cs_as_securable text COLLATE "C" := securable; + cs_as_securable_class text COLLATE "C" := securable_class; + cs_as_permission text COLLATE "C" := permission; + cs_as_sub_securable text COLLATE "C" := sub_securable; + cs_as_sub_securable_class text COLLATE "C" := sub_securable_class; +BEGIN + return_value := NULL; + + -- Lower-case to avoid case issues, remove trailing whitespace to match SQL SERVER behavior + -- Objects created in Babelfish are stored in lower-case in pg_class/pg_proc + cs_as_securable = lower(rtrim(cs_as_securable)); + cs_as_securable_class = lower(rtrim(cs_as_securable_class)); + cs_as_permission = lower(rtrim(cs_as_permission)); + cs_as_sub_securable = lower(rtrim(cs_as_sub_securable)); + cs_as_sub_securable_class = lower(rtrim(cs_as_sub_securable_class)); + + -- Assert that sub_securable and sub_securable_class are either both NULL or both defined + IF cs_as_sub_securable IS NOT NULL AND cs_as_sub_securable_class IS NULL THEN + RETURN NULL; + ELSIF cs_as_sub_securable IS NULL AND cs_as_sub_securable_class IS NOT NULL THEN + RETURN NULL; + -- If they are both defined, user must be evaluating column privileges. + -- Check that inputs are valid for column privileges: sub_securable_class must + -- be column, securable_class must be object, and permission cannot be any. + ELSIF cs_as_sub_securable_class IS NOT NULL + AND (cs_as_sub_securable_class != 'column' + OR cs_as_securable_class IS NULL + OR cs_as_securable_class != 'object' + OR cs_as_permission = 'any') THEN + RETURN NULL; + + -- If securable is null, securable_class must be null + ELSIF cs_as_securable IS NULL AND cs_as_securable_class IS NOT NULL THEN + RETURN NULL; + -- If securable_class is null, securable must be null + ELSIF cs_as_securable IS NOT NULL AND cs_as_securable_class IS NULL THEN + RETURN NULL; + END IF; + + IF cs_as_securable_class = 'server' THEN + -- SQL Server does not permit a securable_class value of 'server'. + -- securable_class should be NULL to evaluate server permissions. + RETURN NULL; + ELSIF cs_as_securable_class IS NULL THEN + -- NULL indicates a server permission. Set this variable so that we can + -- search for the matching entry in babelfish_has_perms_by_name_permissions + cs_as_securable_class = 'server'; + END IF; + + IF cs_as_sub_securable IS NOT NULL THEN + cs_as_sub_securable := babelfish_remove_delimiter_pair(cs_as_sub_securable); + IF cs_as_sub_securable IS NULL THEN + RETURN NULL; + END IF; + END IF; + + SELECT p.implied_dbo_permissions,p.fully_supported + INTO implied_dbo_permissions,fully_supported + FROM babelfish_has_perms_by_name_permissions p + WHERE p.securable_type = cs_as_securable_class AND p.permission_name = cs_as_permission; + + IF implied_dbo_permissions IS NULL OR fully_supported IS NULL THEN + -- Securable class or permission is not valid, or permission is not valid for given securable + RETURN NULL; + END IF; + + IF cs_as_securable_class = 'database' AND cs_as_securable IS NOT NULL THEN + db_name = babelfish_remove_delimiter_pair(cs_as_securable); + IF db_name IS NULL THEN + RETURN NULL; + ELSIF (SELECT COUNT(name) FROM sys.databases WHERE name = db_name) != 1 THEN + RETURN 0; + END IF; + ELSIF cs_as_securable_class = 'schema' THEN + bbf_schema_name = babelfish_remove_delimiter_pair(cs_as_securable); + IF bbf_schema_name IS NULL THEN + RETURN NULL; + ELSIF (SELECT COUNT(nspname) FROM sys.babelfish_namespace_ext ext + WHERE ext.orig_name = bbf_schema_name + AND ext.dbid = sys.db_id()) != 1 THEN + RETURN 0; + END IF; + END IF; + + IF fully_supported = 'f' AND + (SELECT orig_username FROM sys.babelfish_authid_user_ext WHERE rolname = CURRENT_USER) = 'dbo' THEN + RETURN CAST(implied_dbo_permissions AS integer); + ELSIF fully_supported = 'f' THEN + RETURN 0; + END IF; + + -- The only permissions that are fully supported belong to the OBJECT securable class. + -- The block above has dealt with all permissions that are not fully supported, so + -- if we reach this point we know the securable class is OBJECT. + SELECT s.db_name, s.schema_name, s.object_name INTO db_name, bbf_schema_name, object_name + FROM babelfish_split_object_name(cs_as_securable) s; + + -- Invalid securable name + IF object_name IS NULL OR object_name = '' THEN + RETURN NULL; + END IF; + + -- If schema was not specified, use the default + IF bbf_schema_name IS NULL OR bbf_schema_name = '' THEN + bbf_schema_name := sys.schema_name(); + END IF; + + database_id := ( + SELECT CASE + WHEN db_name IS NULL OR db_name = '' THEN (sys.db_id()) + ELSE (sys.db_id(db_name)) + END); + + IF database_id <> sys.db_id() THEN + is_cross_db = true; + END IF; + + userid := ( + SELECT CASE + WHEN is_cross_db THEN sys.suser_id() + ELSE sys.user_id() + END); + + -- Translate schema name from bbf to postgres, e.g. dbo -> master_dbo + pg_schema := (SELECT nspname + FROM sys.babelfish_namespace_ext ext + WHERE ext.orig_name = bbf_schema_name + AND CAST(ext.dbid AS oid) = CAST(database_id AS oid)); + + IF pg_schema IS NULL THEN + -- Shared schemas like sys and pg_catalog do not exist in the table above. + -- These schemas do not need to be translated from Babelfish to Postgres + pg_schema := bbf_schema_name; + END IF; + + -- Surround with double-quotes to handle names that contain periods/spaces + qualified_name := concat('"', pg_schema, '"."', object_name, '"'); + + SELECT oid INTO namespace_id FROM pg_catalog.pg_namespace WHERE nspname = pg_schema COLLATE sys.database_default; + + object_type := ( + SELECT CASE + WHEN cs_as_sub_securable_class = 'column' + THEN CASE + WHEN (SELECT count(a.attname) + FROM pg_attribute a + INNER JOIN pg_class c ON c.oid = a.attrelid + INNER JOIN pg_namespace s ON s.oid = c.relnamespace + WHERE + a.attname = cs_as_sub_securable COLLATE sys.database_default + AND c.relname = object_name COLLATE sys.database_default + AND s.nspname = pg_schema COLLATE sys.database_default + AND NOT a.attisdropped + AND (s.nspname IN (SELECT nspname FROM sys.babelfish_namespace_ext) OR s.nspname = 'sys') + -- r = ordinary table, i = index, S = sequence, t = TOAST table, v = view, m = materialized view, c = composite type, f = foreign table, p = partitioned table + AND c.relkind IN ('r', 'v', 'm', 'f', 'p') + AND a.attnum > 0) = 1 + THEN 'column' + ELSE NULL + END + + WHEN (SELECT count(relname) + FROM pg_catalog.pg_class + WHERE relname = object_name COLLATE sys.database_default + AND relnamespace = namespace_id) = 1 + THEN 'table' + + WHEN (SELECT count(proname) + FROM pg_catalog.pg_proc + WHERE proname = object_name COLLATE sys.database_default + AND pronamespace = namespace_id + AND prokind = 'f') = 1 + THEN 'function' + + WHEN (SELECT count(proname) + FROM pg_catalog.pg_proc + WHERE proname = object_name COLLATE sys.database_default + AND pronamespace = namespace_id + AND prokind = 'p') = 1 + THEN 'procedure' + ELSE NULL + END + ); + + -- Object was not found + IF object_type IS NULL THEN + RETURN 0; + END IF; + + -- Get signature for function-like objects + IF object_type IN('function', 'procedure') THEN + SELECT CAST(oid AS regprocedure) + INTO function_signature + FROM pg_catalog.pg_proc + WHERE proname = object_name COLLATE sys.database_default + AND pronamespace = namespace_id; + END IF; + + return_value := ( + SELECT CASE + WHEN cs_as_permission = 'any' THEN babelfish_has_any_privilege(userid, object_type, pg_schema, object_name) + + WHEN object_type = 'column' + THEN CASE + WHEN cs_as_permission IN('insert', 'delete', 'execute') THEN NULL + ELSE CAST(has_column_privilege(userid, qualified_name, cs_as_sub_securable, cs_as_permission) AS integer) + END + + WHEN object_type = 'table' + THEN CASE + WHEN cs_as_permission = 'execute' THEN 0 + ELSE CAST(has_table_privilege(userid, qualified_name, cs_as_permission) AS integer) + END + + WHEN object_type = 'function' + THEN CASE + WHEN cs_as_permission IN('select', 'execute') + THEN CAST(has_function_privilege(userid, function_signature, 'execute') AS integer) + WHEN cs_as_permission IN('update', 'insert', 'delete', 'references') + THEN 0 + ELSE NULL + END + + WHEN object_type = 'procedure' + THEN CASE + WHEN cs_as_permission = 'execute' + THEN CAST(has_function_privilege(userid, function_signature, 'execute') AS integer) + WHEN cs_as_permission IN('select', 'update', 'insert', 'delete', 'references') + THEN 0 + ELSE NULL + END + + ELSE NULL + END + ); + + RETURN return_value; + EXCEPTION WHEN OTHERS THEN RETURN NULL; +END; +$$; + +GRANT EXECUTE ON FUNCTION sys.has_perms_by_name( + securable sys.SYSNAME, + securable_class sys.nvarchar(60), + permission sys.SYSNAME, + sub_securable sys.SYSNAME, + sub_securable_class sys.nvarchar(60)) TO PUBLIC; + +CREATE OR REPLACE PROCEDURE sys.analyze_babelfish_catalogs() +LANGUAGE plpgsql +AS $$ +DECLARE + babelfish_catalog RECORD; + schema_name varchar = 'sys'; + error_msg text; +BEGIN + FOR babelfish_catalog IN ( + SELECT relname as name from pg_class t + INNER JOIN pg_namespace n on n.oid = t.relnamespace + WHERE t.relkind = 'r' and n.nspname = schema_name + ) + LOOP + BEGIN + EXECUTE format('ANALYZE %I.%I', schema_name, babelfish_catalog.name); + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS error_msg = MESSAGE_TEXT; + RAISE WARNING 'ANALYZE for babelfish catalog %.% failed with error: %s', schema_name, babelfish_catalog.name, error_msg; + END; + END LOOP; +END; +$$; + +-- This is a temporary procedure which is called during upgrade to update guest schema +-- for the guest users in the already existing databases +CREATE OR REPLACE PROCEDURE sys.babelfish_update_user_catalog_for_guest_schema() +LANGUAGE C +AS 'babelfishpg_tsql', 'update_user_catalog_for_guest_schema'; + +CALL sys.babelfish_update_user_catalog_for_guest_schema(); + +ALTER VIEW sys.types RENAME TO types_deprecated_3_4_0; + +create or replace view sys.types As +-- For System types +select + tsql_type_name as name + , t.oid as system_type_id + , t.oid as user_type_id + , s.oid as schema_id + , cast(NULL as INT) as principal_id + , sys.tsql_type_max_length_helper(tsql_type_name, t.typlen, t.typtypmod, true) as max_length + , cast(sys.tsql_type_precision_helper(tsql_type_name, t.typtypmod) as int) as precision + , cast(sys.tsql_type_scale_helper(tsql_type_name, t.typtypmod, false) as int) as scale + , CASE c.collname + WHEN 'default' THEN default_collation_name + ELSE c.collname + END as collation_name + , case when typnotnull then cast(0 as sys.bit) else cast(1 as sys.bit) end as is_nullable + , 0 as is_user_defined + , 0 as is_assembly_type + , 0 as default_object_id + , 0 as rule_object_id + , 0 as is_table_type +from pg_type t +inner join pg_namespace s on s.oid = t.typnamespace +left join pg_collation c on c.oid = t.typcollation +, sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name +,cast(current_setting('babelfishpg_tsql.server_collation_name') as name) as default_collation_name +where +tsql_type_name IS NOT NULL +and pg_type_is_visible(t.oid) +and (s.nspname = 'pg_catalog' OR s.nspname = 'sys') +union all +-- For User Defined Types +select cast(t.typname as text) as name + , t.typbasetype as system_type_id + , t.oid as user_type_id + , t.typnamespace as schema_id + , null::integer as principal_id + , case when tt.typrelid is not null then -1::smallint else sys.tsql_type_max_length_helper(tsql_base_type_name, t.typlen, t.typtypmod) end as max_length + , case when tt.typrelid is not null then 0::smallint else cast(sys.tsql_type_precision_helper(tsql_base_type_name, t.typtypmod) as int) end as precision + , case when tt.typrelid is not null then 0::smallint else cast(sys.tsql_type_scale_helper(tsql_base_type_name, t.typtypmod, false) as int) end as scale + , CASE c.collname + WHEN 'default' THEN default_collation_name + ELSE c.collname + END as collation_name + , case when tt.typrelid is not null then cast(0 as sys.bit) + else case when typnotnull then cast(0 as sys.bit) else cast(1 as sys.bit) end + end + as is_nullable + -- CREATE TYPE ... FROM is implemented as CREATE DOMAIN in babel + , 1 as is_user_defined + , 0 as is_assembly_type + , 0 as default_object_id + , 0 as rule_object_id + , case when tt.typrelid is not null then 1 else 0 end as is_table_type +from pg_type t +join sys.schemas sch on t.typnamespace = sch.schema_id +left join pg_collation c on c.oid = t.typcollation +left join sys.table_types_internal tt on t.typrelid = tt.typrelid +, sys.translate_pg_type_to_tsql(t.oid) AS tsql_type_name +, sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_base_type_name +, cast(current_setting('babelfishpg_tsql.server_collation_name') as name) as default_collation_name +-- we want to show details of user defined datatypes created under babelfish database +where + tsql_type_name IS NULL +and + ( + -- show all user defined datatypes created under babelfish database except table types + t.typtype = 'd' + or + -- only for table types + tt.typrelid is not null + ); +GRANT SELECT ON sys.types TO PUBLIC; + + +ALTER VIEW sys.table_types RENAME TO table_types_deprecated_3_4_0; +create or replace view sys.table_types as +select st.* + , pt.typrelid::int as type_table_object_id + , 0::sys.bit as is_memory_optimized -- return 0 until we support in-memory tables +from sys.types st +inner join pg_catalog.pg_type pt on st.user_type_id = pt.oid +where is_table_type = 1; +GRANT SELECT ON sys.table_types TO PUBLIC; + + + +CREATE OR REPLACE VIEW sys.sp_special_columns_view AS +SELECT +CAST(1 AS SMALLINT) AS SCOPE, +CAST(coalesce (split_part(a.attoptions[1] COLLATE "C", '=', 2) ,a.attname) AS sys.sysname) AS COLUMN_NAME, -- get original column name if exists +CAST(t6.data_type AS SMALLINT) AS DATA_TYPE, + +CASE -- cases for when they are of type identity. + WHEN a.attidentity <> ''::"char" AND (t1.name = 'decimal' OR t1.name = 'numeric') + THEN CAST(CONCAT(t1.name, '() identity') AS sys.sysname) + WHEN a.attidentity <> ''::"char" AND (t1.name != 'decimal' AND t1.name != 'numeric') + THEN CAST(CONCAT(t1.name, ' identity') AS sys.sysname) + ELSE CAST(t1.name AS sys.sysname) +END AS TYPE_NAME, + +CAST(sys.sp_special_columns_precision_helper(COALESCE(tsql_type_name, tsql_base_type_name), c1.precision, c1.max_length, t6."PRECISION") AS INT) AS PRECISION, +CAST(sys.sp_special_columns_length_helper(coalesce(tsql_type_name, tsql_base_type_name), c1.precision, c1.max_length, t6."PRECISION") AS INT) AS LENGTH, +CAST(sys.sp_special_columns_scale_helper(coalesce(tsql_type_name, tsql_base_type_name), c1.scale) AS SMALLINT) AS SCALE, +CAST(1 AS smallint) AS PSEUDO_COLUMN, +CASE + WHEN a.attnotnull + THEN CAST(0 AS INT) + ELSE CAST(1 AS INT) END +AS IS_NULLABLE, +CAST(nsp_ext.dbname AS sys.sysname) AS TABLE_QUALIFIER, +CAST(s1.name AS sys.sysname) AS TABLE_OWNER, +CAST(C.relname AS sys.sysname) AS TABLE_NAME, + +CASE + WHEN X.indisprimary + THEN CAST('p' AS sys.sysname) + ELSE CAST('u' AS sys.sysname) -- if it is a unique index, then we should cast it as 'u' for filtering purposes +END AS CONSTRAINT_TYPE, +CAST(I.relname AS sys.sysname) CONSTRAINT_NAME, +CAST(X.indexrelid AS int) AS INDEX_ID + +FROM( pg_index X +JOIN pg_class C ON X.indrelid = C.oid +JOIN pg_class I ON I.oid = X.indexrelid +CROSS JOIN LATERAL unnest(X.indkey) AS ak(k) + LEFT JOIN pg_attribute a + ON (a.attrelid = X.indrelid AND a.attnum = ak.k) +) +LEFT JOIN sys.pg_namespace_ext nsp_ext ON C.relnamespace = nsp_ext.oid +LEFT JOIN sys.schemas s1 ON s1.schema_id = C.relnamespace +LEFT JOIN sys.columns c1 ON c1.object_id = X.indrelid AND cast(a.attname AS sys.sysname) = c1.name COLLATE sys.database_default +LEFT JOIN pg_catalog.pg_type AS T ON T.oid = c1.system_type_id +LEFT JOIN sys.types AS t1 ON a.atttypid = t1.user_type_id +LEFT JOIN sys.sp_datatype_info_helper(2::smallint, false) AS t6 ON T.typname = t6.pg_type_name OR T.typname = t6.type_name --need in order to get accurate DATA_TYPE value +, sys.translate_pg_type_to_tsql(t1.user_type_id) AS tsql_type_name +, sys.translate_pg_type_to_tsql(t1.system_type_id) AS tsql_base_type_name +WHERE has_schema_privilege(s1.schema_id, 'USAGE') +AND X.indislive ; + +GRANT SELECT ON sys.sp_special_columns_view TO PUBLIC; + + +CREATE OR REPLACE VIEW sys.sp_sproc_columns_view +AS +SELECT +CAST(sys.db_name() AS sys.sysname) AS PROCEDURE_QUALIFIER -- This will always be objects in current database +, CAST(ss.schema_name AS sys.sysname) AS PROCEDURE_OWNER +, CAST( +CASE + WHEN ss.prokind = 'p' THEN CONCAT(ss.proname, ';1') + ELSE CONCAT(ss.proname, ';0') +END +AS sys.nvarchar(134)) AS PROCEDURE_NAME +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN '@TABLE_RETURN_VALUE' + ELSE '@RETURN_VALUE' + END +ELSE COALESCE(ss.proargnames[n], '') +END +AS sys.SYSNAME) AS COLUMN_NAME +, CAST( +CASE +WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 3 + ELSE 5 + END +WHEN ss.proargmodes[n] in ('o', 'b') THEN 2 +ELSE 1 +END +AS smallint) AS COLUMN_TYPE +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.prokind = 'p' THEN (SELECT data_type FROM sys.spt_datatype_info_table WHERE type_name = 'int') + WHEN ss.proretset THEN NULL + ELSE sdit.data_type + END + WHEN st.is_table_type = 1 THEN -153 + ELSE sdit.data_type +END +AS smallint) AS DATA_TYPE +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 'table' + WHEN ss.prokind = 'p' THEN 'int' + ELSE st.name + END + ELSE st.name +END +AS sys.sysname) AS TYPE_NAME +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 0 + WHEN ss.prokind = 'p' THEN (SELECT precision FROM sys.types WHERE name = 'int') + ELSE st.precision + END + WHEN st.is_table_type = 1 THEN 0 + ELSE st.precision +END +AS sys.int) AS PRECISION +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 0 + WHEN ss.prokind = 'p' THEN (SELECT max_length FROM sys.types WHERE name = 'int') + ELSE st.max_length + END + WHEN st.is_table_type = 1 THEN 2147483647 + ELSE st.max_length +END +AS sys.int) AS LENGTH +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 0 + WHEN ss.prokind = 'p' THEN (SELECT scale FROM sys.types WHERE name = 'int') + ELSE st.scale + END + WHEN st.is_table_type = 1 THEN NULL + ELSE st.scale +END +AS smallint) AS SCALE +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 0 + WHEN ss.prokind = 'p' THEN (SELECT num_prec_radix FROM sys.spt_datatype_info_table WHERE type_name = 'int') + ELSE sdit.num_prec_radix + END + WHEN st.is_table_type = 1 THEN NULL + ELSE sdit.num_prec_radix +END +AS smallint) AS RADIX +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset OR ss.prokind = 'p' THEN 0 + ELSE sdit.nullable + END + WHEN st.is_table_type = 1 THEN 1 + ELSE sdit.nullable +END +AS smallint) AS NULLABLE +, CAST( +CASE + WHEN ss.n IS NULL AND ss.proretset THEN 'Result table returned by table valued function' + ELSE NULL +END +AS sys.varchar(254)) COLLATE sys.database_default AS REMARKS +, CAST(NULL AS sys.nvarchar(4000)) AS COLUMN_DEF +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN NULL + WHEN ss.prokind = 'p' THEN (SELECT sql_data_type FROM sys.spt_datatype_info_table WHERE type_name = 'int') + ELSE sdit.sql_data_type + END + WHEN st.is_table_type = 1 THEN -153 + ELSE sdit.sql_data_type +END +AS smallint) AS SQL_DATA_TYPE +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 0 + WHEN ss.prokind = 'p' THEN (SELECT sql_datetime_sub FROM sys.spt_datatype_info_table WHERE type_name = 'int') + ELSE sdit.sql_datetime_sub + END + ELSE sdit.sql_datetime_sub +END +AS smallint) AS SQL_DATETIME_SUB +, CAST( +CASE + WHEN ss.n IS NOT NULL AND st.is_table_type = 1 THEN 2147483647 + ELSE NULL +END +AS sys.int) AS CHAR_OCTET_LENGTH +, CAST( +CASE + WHEN ss.n IS NULL THEN 0 + ELSE n +END +AS sys.int) AS ORDINAL_POSITION +, CAST( +CASE + WHEN ss.n IS NULL AND ss.proretset THEN 'NO' + WHEN st.is_table_type = 1 THEN 'YES' + WHEN sdit.nullable = 1 THEN 'YES' + ELSE 'NO' +END +AS sys.varchar(254)) COLLATE sys.database_default AS IS_NULLABLE +, CAST( +CASE + WHEN ss.n IS NULL THEN + CASE + WHEN ss.proretset THEN 0 + WHEN ss.prokind = 'p' THEN 56 + ELSE sdit.ss_data_type + END + WHEN st.is_table_type = 1 THEN 0 + ELSE sdit.ss_data_type +END +AS sys.tinyint) AS SS_DATA_TYPE +, CAST(ss.proname AS sys.sysname) AS original_procedure_name +FROM +( + -- CTE to query procedures related to bbf + WITH bbf_proc AS ( + SELECT + p.proname as proname, + p.proargnames as proargnames, + p.proargmodes as proargmodes, + p.prokind as prokind, + p.proretset as proretset, + p.prorettype as prorettype, + p.proallargtypes as proallargtypes, + p.proargtypes as proargtypes, + s.name as schema_name + FROM + pg_proc p + INNER JOIN ( + SELECT name as name, schema_id as id FROM sys.schemas + UNION ALL + SELECT CAST(nspname as sys.sysname) as name, CAST(oid as int) as id + from pg_namespace WHERE nspname in ('sys', 'information_schema') + ) as s ON p.pronamespace = s.id + WHERE ( + (pg_has_role(p.proowner, 'USAGE') OR has_function_privilege(p.oid, 'EXECUTE')) + AND (s.name != 'sys' + OR p.proname like 'sp\_%' -- filter out internal babelfish-specific procs in sys schema + OR p.proname like 'xp\_%' + OR p.proname like 'dm\_%' + OR p.proname like 'fn\_%')) + ) + + SELECT * + FROM ( + SELECT -- Selects all parameters (input and output), but NOT return values + p.proname as proname, + p.proargnames as proargnames, + p.proargmodes as proargmodes, + p.prokind as prokind, + p.proretset as proretset, + p.prorettype as prorettype, + p.schema_name as schema_name, + (information_schema._pg_expandarray( + COALESCE(p.proallargtypes, + CASE + WHEN p.prokind = 'f' THEN (CAST(p.proargtypes AS oid[])) + ELSE CAST(p.proargtypes AS oid[]) + END + ))).x AS x, + (information_schema._pg_expandarray( + COALESCE(p.proallargtypes, + CASE + WHEN p.prokind = 'f' THEN (CAST(p.proargtypes AS oid[])) + ELSE CAST(p.proargtypes AS oid[]) + END + ))).n AS n + FROM bbf_proc p) AS t + WHERE (t.proargmodes[t.n] in ('i', 'o', 'b') OR t.proargmodes is NULL) + + UNION ALL + + SELECT -- Selects all return values (this is because inline-table functions could cause duplicate outputs) + p.proname as proname, + p.proargnames as proargnames, + p.proargmodes as proargmodes, + p.prokind as prokind, + p.proretset as proretset, + p.prorettype as prorettype, + p.schema_name as schema_name, + p.prorettype AS x, + NULL AS n -- null value indicates that we are retrieving the return values of the proc/func + FROM bbf_proc p +) ss +LEFT JOIN sys.types st ON ss.x = st.user_type_id -- left joined because return type of table-valued functions may not have an entry in sys.types +-- Because spt_datatype_info_table does contain user-defind types and their names, +-- the join below allows us to retrieve the name of the base type of the user-defined type +LEFT JOIN sys.spt_datatype_info_table sdit ON sdit.type_name = sys.translate_pg_type_to_tsql(st.system_type_id); +GRANT SELECT ON sys.sp_sproc_columns_view TO PUBLIC; + + + +CREATE OR REPLACE VIEW sys.assembly_types +AS +SELECT + CAST(t.name as sys.sysname) AS name, + -- 'system_type_id' is specified as type INT here, and not TINYINT per SQL Server documentation. + -- This is because the IDs of generated SQL Server system type values generated by B + -- Babelfish installation will exceed the size of TINYINT. + CAST(t.system_type_id as int) AS system_type_id, + CAST(t.user_type_id as int) AS user_type_id, + CAST(t.schema_id as int) AS schema_id, + CAST(t.principal_id as int) AS principal_id, + CAST(t.max_length as smallint) AS max_length, + CAST(t.precision as sys.tinyint) AS precision, + CAST(t.scale as sys.tinyint) AS scale, + CAST(t.collation_name as sys.sysname) AS collation_name, + CAST(t.is_nullable as sys.bit) AS is_nullable, + CAST(t.is_user_defined as sys.bit) AS is_user_defined, + CAST(t.is_assembly_type as sys.bit) AS is_assembly_type, + CAST(t.default_object_id as int) AS default_object_id, + CAST(t.rule_object_id as int) AS rule_object_id, + CAST(NULL as int) AS assembly_id, + CAST(NULL as sys.sysname) AS assembly_class, + CAST(NULL as sys.bit) AS is_binary_ordered, + CAST(NULL as sys.bit) AS is_fixed_length, + CAST(NULL as sys.nvarchar(40)) AS prog_id, + CAST(NULL as sys.nvarchar(4000)) AS assembly_qualified_name, + CAST(t.is_table_type as sys.bit) AS is_table_type +FROM sys.types t +WHERE t.is_assembly_type = 1; +GRANT SELECT ON sys.assembly_types TO PUBLIC; + + + + +CREATE OR REPLACE VIEW sys.all_parameters +AS +SELECT + CAST(ss.p_oid AS INT) AS object_id + , CAST(COALESCE(ss.proargnames[(ss.x).n], '') AS sys.SYSNAME) AS name + , CAST( + CASE + WHEN is_out_scalar = 1 THEN 0 -- param_id = 0 for output of scalar function + ELSE (ss.x).n + END + AS INT) AS parameter_id + -- 'system_type_id' is specified as type INT here, and not TINYINT per SQL Server documentation. + -- This is because the IDs of system type values generated by + -- Babelfish installation will exceed the size of TINYINT + , CAST(st.system_type_id AS INT) AS system_type_id + , CAST(st.user_type_id AS INT) AS user_type_id + , CAST( + CASE + WHEN st.is_table_type = 1 THEN -1 -- TVP case + WHEN st.is_user_defined = 1 THEN st.max_length -- UDT case + ELSE sys.tsql_type_max_length_helper(st.name, t.typlen, typmod, true, true) + END + AS smallint) AS max_length + , CAST( + CASE + WHEN st.is_table_type = 1 THEN 0 -- TVP case + WHEN st.is_user_defined = 1 THEN st.precision -- UDT case + ELSE sys.tsql_type_precision_helper(st.name, typmod) + END + AS sys.tinyint) AS precision + , CAST( + CASE + WHEN st.is_table_type = 1 THEN 0 -- TVP case + WHEN st.is_user_defined = 1 THEN st.scale + ELSE sys.tsql_type_scale_helper(st.name, typmod,false) + END + AS sys.tinyint) AS scale + , CAST( + CASE + WHEN is_out_scalar = 1 THEN 1 -- Output of a scalar function + WHEN ss.proargmodes[(ss.x).n] in ('o', 'b', 't') THEN 1 + ELSE 0 + END + AS sys.bit) AS is_output + , CAST(0 AS sys.bit) AS is_cursor_ref + , CAST(0 AS sys.bit) AS has_default_value + , CAST(0 AS sys.bit) AS is_xml_document + , CAST(NULL AS sys.sql_variant) AS default_value + , CAST(0 AS int) AS xml_collection_id + , CAST(0 AS sys.bit) AS is_readonly + , CAST(1 AS sys.bit) AS is_nullable + , CAST(NULL AS int) AS encryption_type + , CAST(NULL AS sys.nvarchar(64)) AS encryption_type_desc + , CAST(NULL AS sys.sysname) AS encryption_algorithm_name + , CAST(NULL AS int) AS column_encryption_key_id + , CAST(NULL AS sys.sysname) AS column_encryption_key_database_name +FROM pg_type t + INNER JOIN sys.types st ON st.user_type_id = t.oid + INNER JOIN + ( + SELECT + p.oid AS p_oid, + p.proargnames, + p.proargmodes, + p.prokind, + json_extract_path(CAST(p.probin as json), 'typmod_array') AS typmod_array, + information_schema._pg_expandarray( + COALESCE(p.proallargtypes, + CASE + WHEN p.prokind = 'f' THEN (CAST( p.proargtypes AS oid[]) || p.prorettype) -- Adds return type if not present on proallargtypes + ELSE CAST(p.proargtypes AS oid[]) + END + )) AS x + FROM pg_proc p + WHERE ( + p.pronamespace in (select schema_id from sys.schemas union all select oid from pg_namespace where nspname = 'sys') + AND (pg_has_role(p.proowner, 'USAGE') OR has_function_privilege(p.oid, 'EXECUTE')) + AND p.probin like '{%typmod_array%}') -- Needs to have a typmod array in JSON format + ) ss ON t.oid = (ss.x).x, + COALESCE(pg_get_function_result(ss.p_oid), '') AS return_type, + CAST(ss.typmod_array->>(ss.x).n-1 AS INT) AS typmod, + CAST( + CASE + WHEN ss.prokind = 'f' AND ss.proargnames[(ss.x).n] IS NULL THEN 1 -- checks if param is output of scalar function + ELSE 0 + END + AS INT) AS is_out_scalar +WHERE ( -- If it is a Table function, we only want the inputs + return_type NOT LIKE 'TABLE(%' OR + (return_type LIKE 'TABLE(%' AND ss.proargmodes[(ss.x).n] = 'i')); +GRANT SELECT ON sys.all_parameters TO PUBLIC; + + +CREATE OR REPLACE VIEW sys.systypes AS +SELECT CAST(name as sys.sysname) as name + , CAST(system_type_id as int) as xtype + , CAST((case when is_nullable = 1 then 0 else 1 end) as sys.tinyint) as status + , CAST((case when user_type_id < 32767 then user_type_id::int else null end) as smallint) as xusertype + , max_length as length + , CAST(precision as sys.tinyint) as xprec + , CAST(scale as sys.tinyint) as xscale + , CAST(default_object_id as int) as tdefault + , CAST(rule_object_id as int) as domain + , CAST((case when schema_id < 32767 then schema_id::int else null end) as smallint) as uid + , CAST(0 as smallint) as reserved + , CAST(sys.CollationProperty(collation_name, 'CollationId') as int) as collationid + , CAST((case when user_type_id < 32767 then user_type_id::int else null end) as smallint) as usertype + , CAST((case when (coalesce(sys.translate_pg_type_to_tsql(system_type_id), sys.translate_pg_type_to_tsql(user_type_id)) + in ('nvarchar', 'varchar', 'sysname', 'varbinary')) then 1 + else 0 end) as sys.bit) as variable + , CAST(is_nullable as sys.bit) as allownulls + , CAST(system_type_id as int) as type + , CAST(null as sys.varchar(255)) as printfmt + , (case when precision <> 0::smallint then precision + else sys.systypes_precision_helper(sys.translate_pg_type_to_tsql(system_type_id), max_length) end) as prec + , CAST(scale as sys.tinyint) as scale + , CAST(collation_name as sys.sysname) as collation +FROM sys.types; +GRANT SELECT ON sys.systypes TO PUBLIC; + +create or replace view sys.all_objects as +select + cast (name as sys.sysname) collate sys.database_default + , cast (object_id as integer) + , cast ( principal_id as integer) + , cast (schema_id as integer) + , cast (parent_object_id as integer) + , cast (type as char(2)) collate sys.database_default + , cast (type_desc as sys.nvarchar(60)) + , cast (create_date as sys.datetime) + , cast (modify_date as sys.datetime) + , cast (case when (schema_id::regnamespace::text = 'sys') then 1 + when name in (select name from sys.shipped_objects_not_in_sys nis + where nis.name = name and nis.schemaid = schema_id and nis.type = type) then 1 + else 0 end as sys.bit) as is_ms_shipped + , cast (is_published as sys.bit) + , cast (is_schema_published as sys.bit) +from +( +-- details of user defined and system tables +select + t.relname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'U' as type + , 'USER_TABLE' as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relpersistence in ('p', 'u', 't') +and t.relkind = 'r' +and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and not sys.is_table_type(t.oid) +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(t.oid, 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +union all +-- details of user defined and system views +select + t.relname as name + , t.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'V'::varchar(2) as type + , 'VIEW'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class t inner join pg_namespace s on s.oid = t.relnamespace +where t.relkind = 'v' +and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +and has_table_privilege(quote_ident(s.nspname) ||'.'||quote_ident(t.relname), 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE,TRIGGER') +union all +-- details of user defined and system foreign key constraints +select + c.conname as name + , c.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , c.conrelid as parent_object_id + , 'F' as type + , 'FOREIGN_KEY_CONSTRAINT' + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +and c.contype = 'f' +union all +-- details of user defined and system primary key constraints +select + c.conname as name + , c.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , c.conrelid as parent_object_id + , 'PK' as type + , 'PRIMARY_KEY_CONSTRAINT' as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_constraint c +inner join pg_namespace s on s.oid = c.connamespace +where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +and c.contype = 'p' +union all +-- details of user defined and system defined procedures +select + p.proname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , cast (case when tr.tgrelid is not null + then tr.tgrelid + else 0 end as int) + as parent_object_id + , case p.prokind + when 'p' then 'P'::varchar(2) + when 'a' then 'AF'::varchar(2) + else + case + when pg_catalog.format_type(p.prorettype, null) = 'trigger' + then 'TR'::varchar(2) + when p.proretset then + case + when t.typtype = 'c' + then 'TF'::varchar(2) + else 'IF'::varchar(2) + end + else 'FN'::varchar(2) + end + end as type + , case p.prokind + when 'p' then 'SQL_STORED_PROCEDURE'::varchar(60) + when 'a' then 'AGGREGATE_FUNCTION'::varchar(60) + else + case + when pg_catalog.format_type(p.prorettype, null) = 'trigger' + then 'SQL_TRIGGER'::varchar(60) + when p.proretset then + case + when t.typtype = 'c' + then 'SQL_TABLE_VALUED_FUNCTION'::varchar(60) + else 'SQL_INLINE_TABLE_VALUED_FUNCTION'::varchar(60) + end + else 'SQL_SCALAR_FUNCTION'::varchar(60) + end + end as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_proc p +inner join pg_namespace s on s.oid = p.pronamespace +inner join pg_catalog.pg_type t on t.oid = p.prorettype +left join pg_trigger tr on tr.tgfoid = p.oid +where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +and has_function_privilege(p.oid, 'EXECUTE') +union all +-- details of all default constraints +select + ('DF_' || o.relname || '_' || d.oid)::name as name + , d.oid as object_id + , null::int as principal_id + , o.relnamespace as schema_id + , d.adrelid as parent_object_id + , 'D'::char(2) as type + , 'DEFAULT_CONSTRAINT'::sys.nvarchar(60) AS type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_catalog.pg_attrdef d +inner join pg_attribute a on a.attrelid = d.adrelid and d.adnum = a.attnum +inner join pg_class o on d.adrelid = o.oid +inner join pg_namespace s on s.oid = o.relnamespace +where a.atthasdef = 't' and a.attgenerated = '' +and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +and has_column_privilege(a.attrelid, a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') +union all +-- details of all check constraints +select + c.conname::name + , c.oid::integer as object_id + , NULL::integer as principal_id + , c.connamespace::integer as schema_id + , c.conrelid::integer as parent_object_id + , 'C'::char(2) as type + , 'CHECK_CONSTRAINT'::sys.nvarchar(60) as type_desc + , null::sys.datetime as create_date + , null::sys.datetime as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_catalog.pg_constraint as c +inner join pg_namespace s on s.oid = c.connamespace +where (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +and c.contype = 'c' and c.conrelid != 0 +union all +-- details of user defined and system defined sequence objects +select + p.relname as name + , p.oid as object_id + , null::integer as principal_id + , s.oid as schema_id + , 0 as parent_object_id + , 'SO'::varchar(2) as type + , 'SEQUENCE_OBJECT'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 0 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from pg_class p +inner join pg_namespace s on s.oid = p.relnamespace +where p.relkind = 'S' +and (s.oid in (select schema_id from sys.schemas) or s.nspname = 'sys') +and has_schema_privilege(s.oid, 'USAGE') +union all +-- details of user defined table types +select + ('TT_' || tt.name || '_' || tt.type_table_object_id)::name as name + , tt.type_table_object_id as object_id + , tt.principal_id as principal_id + , tt.schema_id as schema_id + , 0 as parent_object_id + , 'TT'::varchar(2) as type + , 'TABLE_TYPE'::varchar(60) as type_desc + , null::timestamp as create_date + , null::timestamp as modify_date + , 1 as is_ms_shipped + , 0 as is_published + , 0 as is_schema_published +from sys.table_types tt +) ot; +GRANT SELECT ON sys.all_objects TO PUBLIC; + + + +create or replace view sys.objects as +select + CAST(t.name as sys.sysname) as name + , CAST(t.object_id as int) as object_id + , CAST(t.principal_id as int) as principal_id + , CAST(t.schema_id as int) as schema_id + , CAST(t.parent_object_id as int) as parent_object_id + , CAST('U' as char(2)) as type + , CAST('USER_TABLE' as sys.nvarchar(60)) as type_desc + , CAST(t.create_date as sys.datetime) as create_date + , CAST(t.modify_date as sys.datetime) as modify_date + , CAST(t.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(t.is_published as sys.bit) as is_published + , CAST(t.is_schema_published as sys.bit) as is_schema_published +from sys.tables t +union all +select + CAST(v.name as sys.sysname) as name + , CAST(v.object_id as int) as object_id + , CAST(v.principal_id as int) as principal_id + , CAST(v.schema_id as int) as schema_id + , CAST(v.parent_object_id as int) as parent_object_id + , CAST('V' as char(2)) as type + , CAST('VIEW' as sys.nvarchar(60)) as type_desc + , CAST(v.create_date as sys.datetime) as create_date + , CAST(v.modify_date as sys.datetime) as modify_date + , CAST(v.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(v.is_published as sys.bit) as is_published + , CAST(v.is_schema_published as sys.bit) as is_schema_published +from sys.views v +union all +select + CAST(f.name as sys.sysname) as name + , CAST(f.object_id as int) as object_id + , CAST(f.principal_id as int) as principal_id + , CAST(f.schema_id as int) as schema_id + , CAST(f.parent_object_id as int) as parent_object_id + , CAST('F' as char(2)) as type + , CAST('FOREIGN_KEY_CONSTRAINT' as sys.nvarchar(60)) as type_desc + , CAST(f.create_date as sys.datetime) as create_date + , CAST(f.modify_date as sys.datetime) as modify_date + , CAST(f.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(f.is_published as sys.bit) as is_published + , CAST(f.is_schema_published as sys.bit) as is_schema_published + from sys.foreign_keys f +union all +select + CAST(p.name as sys.sysname) as name + , CAST(p.object_id as int) as object_id + , CAST(p.principal_id as int) as principal_id + , CAST(p.schema_id as int) as schema_id + , CAST(p.parent_object_id as int) as parent_object_id + , CAST('PK' as char(2)) as type + , CAST('PRIMARY_KEY_CONSTRAINT' as sys.nvarchar(60)) as type_desc + , CAST(p.create_date as sys.datetime) as create_date + , CAST(p.modify_date as sys.datetime) as modify_date + , CAST(p.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(p.is_published as sys.bit) as is_published + , CAST(p.is_schema_published as sys.bit) as is_schema_published +from sys.key_constraints p +where p.type = 'PK' +union all +select + CAST(pr.name as sys.sysname) as name + , CAST(pr.object_id as int) as object_id + , CAST(pr.principal_id as int) as principal_id + , CAST(pr.schema_id as int) as schema_id + , CAST(pr.parent_object_id as int) as parent_object_id + , CAST(pr.type as char(2)) as type + , CAST(pr.type_desc as sys.nvarchar(60)) as type_desc + , CAST(pr.create_date as sys.datetime) as create_date + , CAST(pr.modify_date as sys.datetime) as modify_date + , CAST(pr.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(pr.is_published as sys.bit) as is_published + , CAST(pr.is_schema_published as sys.bit) as is_schema_published + from sys.procedures pr +union all +select + CAST(tr.name as sys.sysname) as name + , CAST(tr.object_id as int) as object_id + , CAST(NULL as int) as principal_id + , CAST(p.pronamespace as int) as schema_id + , CAST(tr.parent_id as int) as parent_object_id + , CAST(tr.type as char(2)) as type + , CAST(tr.type_desc as sys.nvarchar(60)) as type_desc + , CAST(tr.create_date as sys.datetime) as create_date + , CAST(tr.modify_date as sys.datetime) as modify_date + , CAST(tr.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(0 as sys.bit) as is_published + , CAST(0 as sys.bit) as is_schema_published + from sys.triggers tr + inner join pg_proc p on p.oid = tr.object_id +union all +select + CAST(def.name as sys.sysname) as name + , CAST(def.object_id as int) as object_id + , CAST(def.principal_id as int) as principal_id + , CAST(def.schema_id as int) as schema_id + , CAST(def.parent_object_id as int) as parent_object_id + , CAST(def.type as char(2)) as type + , CAST(def.type_desc as sys.nvarchar(60)) as type_desc + , CAST(def.create_date as sys.datetime) as create_date + , CAST(def.modified_date as sys.datetime) as modify_date + , CAST(def.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(def.is_published as sys.bit) as is_published + , CAST(def.is_schema_published as sys.bit) as is_schema_published + from sys.default_constraints def +union all +select + CAST(chk.name as sys.sysname) as name + , CAST(chk.object_id as int) as object_id + , CAST(chk.principal_id as int) as principal_id + , CAST(chk.schema_id as int) as schema_id + , CAST(chk.parent_object_id as int) as parent_object_id + , CAST(chk.type as char(2)) as type + , CAST(chk.type_desc as sys.nvarchar(60)) as type_desc + , CAST(chk.create_date as sys.datetime) as create_date + , CAST(chk.modify_date as sys.datetime) as modify_date + , CAST(chk.is_ms_shipped as sys.bit) as is_ms_shipped + , CAST(chk.is_published as sys.bit) as is_published + , CAST(chk.is_schema_published as sys.bit) as is_schema_published + from sys.check_constraints chk +union all +select + CAST(p.relname as sys.sysname) as name + , CAST(p.oid as int) as object_id + , CAST(null as int) as principal_id + , CAST(s.schema_id as int) as schema_id + , CAST(0 as int) as parent_object_id + , CAST('SO' as char(2)) as type + , CAST('SEQUENCE_OBJECT' 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(0 as sys.bit) as is_published + , CAST(0 as sys.bit) as is_schema_published +from pg_class p +inner join sys.schemas s on s.schema_id = p.relnamespace +and p.relkind = 'S' +and has_schema_privilege(s.schema_id, 'USAGE') +union all +select + CAST(('TT_' || tt.name collate "C" || '_' || tt.type_table_object_id) as sys.sysname) as name + , CAST(tt.type_table_object_id as int) as object_id + , CAST(tt.principal_id as int) as principal_id + , CAST(tt.schema_id as int) as schema_id + , CAST(0 as int) as parent_object_id + , CAST('TT' as char(2)) as type + , CAST('TABLE_TYPE' as sys.nvarchar(60)) as type_desc + , CAST((select string_agg( + case + when option like 'bbf_rel_create_date=%%' then substring(option, 21) + else NULL + end, ',') + from unnest(c.reloptions) as option) + as sys.datetime) as create_date + , CAST((select string_agg( + case + when option like 'bbf_rel_create_date=%%' then substring(option, 21) + else NULL + end, ',') + from unnest(c.reloptions) as option) + as sys.datetime) as modify_date + , CAST(1 as sys.bit) as is_ms_shipped + , CAST(0 as sys.bit) as is_published + , CAST(0 as sys.bit) as is_schema_published +from sys.table_types tt +inner join pg_class c on tt.type_table_object_id = c.oid; +GRANT SELECT ON sys.objects TO PUBLIC; + +ALTER FUNCTION sys.identity_into_int(INT, INT, INT) RENAME TO identity_into_int_deprecated_in_3_4_0; +ALTER FUNCTION sys.identity_into_smallint(INT, SMALLINT, SMALLINT) RENAME TO identity_into_smallint_deprecated_in_3_4_0; + +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'identity_into_int_deprecated_in_3_4_0'); +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'identity_into_smallint_deprecated_in_3_4_0'); + +CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'types_deprecated_3_4_0'); +CALL sys.babelfish_drop_deprecated_object('view', 'sys', 'table_types_deprecated_3_4_0'); + +-- Drop this procedure after it gets executed once. +DROP PROCEDURE sys.babelfish_update_user_catalog_for_guest_schema(); + +-- tsql full-text search configurations for Babelfish +-- Since currently we only support one language - American English, +-- the configurations are for American English only + +-- create a configuration fts_contains_simple for simple terms search +CREATE TEXT SEARCH DICTIONARY fts_contains_simple_dict ( + TEMPLATE = simple, + STOPWORDS = tsql_contains +); + +COMMENT ON TEXT SEARCH DICTIONARY fts_contains_simple_dict IS 'Babelfish T-SQL full text search CONTAINS dictionary (currently we only support American English)'; + +CREATE TEXT SEARCH CONFIGURATION fts_contains_simple ( COPY = simple ); + +COMMENT ON TEXT SEARCH CONFIGURATION fts_contains_simple IS 'Babelfish T-SQL full text search CONTAINS configuration (currently we only support American English)'; + +ALTER TEXT SEARCH CONFIGURATION fts_contains_simple + ALTER MAPPING FOR asciiword, asciihword, hword_asciipart, + word, hword, hword_part + WITH fts_contains_simple_dict; + + + +-- Create a configuration english_inflectional_babel for inflectional search +-- first english_inflectional_babel is created as a copy of the build-in Postgres english configuration +CREATE TEXT SEARCH DICTIONARY english_stem_babel + (TEMPLATE = snowball, Language = english , StopWords=tsql_contains); + +COMMENT ON TEXT SEARCH DICTIONARY english_stem_babel IS 'snowball stemmer for english_inflectional_babel language'; + +CREATE TEXT SEARCH CONFIGURATION english_inflectional_babel + (PARSER = default); + +COMMENT ON TEXT SEARCH CONFIGURATION english_inflectional_babel IS 'configuration for english_inflectional_babel language'; + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel ADD MAPPING + FOR email, url, url_path, host, file, version, + sfloat, float, int, uint, + numword, hword_numpart, numhword + WITH simple; + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel ADD MAPPING + FOR asciiword, hword_asciipart, asciihword + WITH english_stem_babel; + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel ADD MAPPING + FOR word, hword_part, hword + WITH english_stem_babel; + +-- then we add irregular verbs as synonym files to english_inflectional_babel for inflectional search +CREATE TEXT SEARCH DICTIONARY irregular_verbs ( + TEMPLATE = synonym, + SYNONYMS = irregular_verbs +); + +ALTER TEXT SEARCH CONFIGURATION english_inflectional_babel + ALTER MAPPING FOR asciiword + WITH irregular_verbs, english_stem_babel; + +-- Given the query string, determine the Postgres full text configuration to use +-- Currently we only support simple terms and prefix terms +-- For simple terms, we use the 'fts_contains_simple' configuration +-- For prefix terms, we use the 'simple' configuration +-- They are the configurations that provide closest matching according to our experiments +CREATE OR REPLACE FUNCTION sys.babelfish_fts_contains_pgconfig(IN phrase text) + RETURNS regconfig AS +$$ +DECLARE + joined_text text; + word text; +BEGIN + -- Prefix term (Examples: '"word1*"', '"word1 word2*"') if + -- (1) search term is surrounded by double quotes (Counter example: 'word1*', as it doesn't have double quotes) + -- (2) last word in the search term ends with a star (Counter example: '"word1* word2"', as last word doesn't end with star) + -- (3) last word is NOT a single star (Counter example: '"*"', '"word1 word2 *"', as last word is a single star) + IF (phrase COLLATE C) SIMILAR TO ('[ ]*"%\*"[ ]*' COLLATE C) AND (NOT (phrase COLLATE C) SIMILAR TO ('[ ]*"% \*"[ ]*' COLLATE C)) AND (NOT (phrase COLLATE C) SIMILAR TO ('[ ]*"\*"[ ]*' COLLATE C)) THEN + RETURN 'simple'::regconfig; + END IF; + + -- Generation term, inflectional (Examples: 'FORMSOF(INFLECTIONAL, love)', 'FORMSOF(INFLECTIONAL, "move forward")', 'FORMSOF(INFLECTIONAL, play, "plan to")') + IF UPPER(phrase COLLATE C) SIMILAR TO ('[ ]*FORMSOF\(INFLECTIONAL,%\)[ ]*' COLLATE C) THEN + RETURN 'english_inflectional_babel'::regconfig; + END IF; + + -- Generation term, thesaurus (Examples: 'FORMSOF(THESAURUS, love)', 'FORMSOF(THESAURUS, "move forward")', 'FORMSOF(THESAURUS, play, "plan to")') + -- By default, SQL Server thesaurus search does not use any thesaurus files so behavior is identical to simple terms + IF UPPER(phrase COLLATE C) SIMILAR TO ('[ ]*FORMSOF\(THESAURUS,%\)[ ]*' COLLATE C) THEN + RETURN 'fts_contains_simple'::regconfig; + END IF; + + -- Simple term + RETURN 'fts_contains_simple'::regconfig; +END; +$$ +LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE; + +-- This function performs string rewriting for the full text search CONTAINS predicate +-- in Babelfish +-- For example, a T-SQL query +-- SELECT * FROM t WHERE CONTAINS(txt, '"good old days"') +-- is rewritten into a Postgres query +-- SELECT * FROM t WHERE to_tsvector('fts_contains', txt) @@ to_tsquery('fts_contains', 'good <-> old <-> days') +-- In particular, the string constant '"good old days"' gets rewritten into 'good <-> old <-> days' +-- This function performs the string rewriting from '"good old days"' to 'good <-> old <-> days' +-- For prefix terms, '"word1*"' is rewritten into 'word1:*', and '"word1 word2 word3*"' is rewritten into 'word1<->word2<->word3:*' +CREATE OR REPLACE FUNCTION sys.babelfish_fts_rewrite(IN phrase text) RETURNS TEXT AS +'babelfishpg_tsql', 'babelfish_fts_rewrite' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +DO $$ +DECLARE + exception_message text; +BEGIN + -- Rename format_datetime function for dependencies + ALTER FUNCTION sys.format_datetime(anyelement, NVARCHAR, VARCHAR, VARCHAR) RENAME TO format_datetime_deprecated_3_4_0; + + CREATE OR REPLACE FUNCTION sys.format_datetime(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '') RETURNS sys.nvarchar + AS 'babelfishpg_tsql', 'format_datetime' LANGUAGE C IMMUTABLE PARALLEL UNSAFE; + GRANT EXECUTE ON FUNCTION sys.format_datetime(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR) TO PUBLIC; + + -- === DROP format_datetime_deprecated_3_4_0 + CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_datetime_deprecated_3_4_0'); + +EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + exception_message = MESSAGE_TEXT; + RAISE WARNING '%', exception_message; +END; +$$; + +DO $$ +DECLARE + exception_message text; +BEGIN + -- Rename format_numeric for dependencies + ALTER FUNCTION sys.format_numeric(anyelement, NVARCHAR, VARCHAR, VARCHAR, int) RENAME TO format_numeric_deprecated_3_4_0; + + CREATE OR REPLACE FUNCTION sys.format_numeric(IN value anyelement, IN format_pattern sys.NVARCHAR,IN culture sys.VARCHAR, IN data_type sys.VARCHAR DEFAULT '', IN e_position INT DEFAULT -1) RETURNS sys.nvarchar + AS 'babelfishpg_tsql', 'format_numeric' LANGUAGE C IMMUTABLE PARALLEL UNSAFE; + GRANT EXECUTE ON FUNCTION sys.format_numeric(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR, IN sys.VARCHAR, IN INT) TO PUBLIC; + + -- === DROP format_numeric_deprecated_3_4_0 + CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_numeric_deprecated_3_4_0'); + +EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + exception_message = MESSAGE_TEXT; + RAISE WARNING '%', exception_message; +END; +$$; + +DO $$ +DECLARE + exception_message text; +BEGIN + -- Rename FORMAT for dependencies + ALTER FUNCTION sys.FORMAT(anyelement, NVARCHAR, VARCHAR) RENAME TO format_deprecated_3_4_0; + + CREATE OR REPLACE FUNCTION sys.FORMAT(IN arg anyelement, IN p_format_pattern sys.NVARCHAR, IN p_culture sys.VARCHAR default 'en-us') + RETURNS sys.NVARCHAR + AS + $BODY$ + DECLARE + arg_type regtype; + v_temp_integer INTEGER; + BEGIN + arg_type := pg_typeof(arg); + + CASE + WHEN arg_type IN ('time'::regtype ) THEN + RETURN sys.format_datetime(arg, p_format_pattern, p_culture, 'time'); + + WHEN arg_type IN ('date'::regtype, 'sys.datetime'::regtype, 'sys.smalldatetime'::regtype, 'sys.datetime2'::regtype ) THEN + RETURN sys.format_datetime(arg::timestamp, p_format_pattern, p_culture); + + WHEN arg_type IN ('sys.tinyint'::regtype) THEN + RETURN sys.format_numeric(arg::SMALLINT, p_format_pattern, p_culture, 'tinyint'); + + WHEN arg_type IN ('smallint'::regtype) THEN + RETURN sys.format_numeric(arg::SMALLINT, p_format_pattern, p_culture, 'smallint'); + + WHEN arg_type IN ('integer'::regtype) THEN + RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'integer'); + + WHEN arg_type IN ('bigint'::regtype) THEN + RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'bigint'); + + WHEN arg_type IN ('numeric'::regtype) THEN + RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'numeric'); + + WHEN arg_type IN ('sys.decimal'::regtype) THEN + RETURN sys.format_numeric(arg::numeric, p_format_pattern, p_culture, 'numeric'); + + WHEN arg_type IN ('real'::regtype) THEN + IF(p_format_pattern LIKE 'R%') THEN + v_temp_integer := length(nullif((regexp_matches(arg::real::text, '(?<=\d*\.).*(?=[eE].*)')::text[])[1], '')); + ELSE v_temp_integer:= -1; + END IF; + + RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'real', v_temp_integer); + + WHEN arg_type IN ('float'::regtype) THEN + RETURN sys.format_numeric(arg, p_format_pattern, p_culture, 'float'); + + WHEN pg_typeof(arg) IN ('sys.smallmoney'::regtype, 'sys.money'::regtype) THEN + RETURN sys.format_numeric(arg::numeric, p_format_pattern, p_culture, 'numeric'); + ELSE + RAISE datatype_mismatch; + END CASE; + EXCEPTION + WHEN datatype_mismatch THEN + RAISE USING MESSAGE := format('Argument data type % is invalid for argument 1 of format function.', pg_typeof(arg)), + DETAIL := 'Invalid datatype.', + HINT := 'Convert it to valid datatype and try again.'; + END; + $BODY$ + LANGUAGE plpgsql IMMUTABLE PARALLEL UNSAFE; + GRANT EXECUTE ON FUNCTION sys.FORMAT(IN anyelement, IN sys.NVARCHAR, IN sys.VARCHAR) TO PUBLIC; + + -- === DROP format_deprecated_3_4_0 + CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'format_deprecated_3_4_0'); + +EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + exception_message = MESSAGE_TEXT; + RAISE WARNING '%', exception_message; +END; +$$; + +CREATE OR REPLACE FUNCTION sys.bbf_pivot() +RETURNS setof record +AS 'babelfishpg_tsql', 'bbf_pivot' +LANGUAGE C STABLE; + +CREATE OR REPLACE VIEW sys.babelfish_configurations_view as + SELECT * + FROM pg_catalog.pg_settings + WHERE name collate "C" like 'babelfishpg_tsql.explain_%' OR + name collate "C" like 'babelfishpg_tsql.escape_hatch_%' OR + name collate "C" = 'babelfishpg_tsql.enable_pg_hint' OR + name collate "C" like 'babelfishpg_tsql.isolation_level_%'; +GRANT SELECT on sys.babelfish_configurations_view TO PUBLIC; + +-- Change the owner of the current database. +-- This is a wrapper around ALTER AUTHORIZATION ON DATABASE:: +CREATE OR REPLACE PROCEDURE sys.sp_changedbowner( + IN "@loginame" sys.sysname, + IN "@map" sys.VARCHAR(5) DEFAULT NULL) -- this parameter is ignored in T-SQL +LANGUAGE 'pltsql' +AS $$ +BEGIN + DECLARE @cmd sys.NVARCHAR(300) + DECLARE @db sys.sysname = DB_NAME() + + -- For a NULL login name, do nothing + IF @loginame IS NULL + BEGIN + RETURN + END + + IF (@db = 'master') OR (@db = 'tempdb') + BEGIN + RAISERROR('Cannot change the owner of the master or tempdb database.', 16, 1) + RETURN + END + + IF SUSER_ID(@loginame) IS NULL + BEGIN + RAISERROR('Cannot find the principal ''%s'', because it does not exist or you do not have permission.', 16, 1, @loginame) + RETURN + END + + -- Compose the ALTER ATHORIZATION statement: + SET @cmd = 'ALTER AUTHORIZATION ON DATABASE::[' + @db + '] TO [' + SUSER_NAME(SUSER_ID(@loginame)) + ']' + EXECUTE(@cmd) +END +$$; +GRANT EXECUTE ON PROCEDURE sys.sp_changedbowner(IN sys.sysname, IN sys.VARCHAR(5)) TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.getdate() RETURNS sys.datetime +AS 'babelfishpg_tsql', 'getdate_internal' +LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.getdate() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sysdatetime() RETURNS datetime2 +AS 'babelfishpg_tsql', 'sysdatetime' +LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.sysdatetime() TO PUBLIC; + +CREATE OR REPLACE FUNCTION sys.sysdatetimeoffset() RETURNS sys.datetimeoffset +AS 'babelfishpg_tsql', 'sysdatetimeoffset' +LANGUAGE C STABLE; +GRANT EXECUTE ON FUNCTION sys.sysdatetimeoffset() TO PUBLIC; + +ALTER FUNCTION sys.datediff_internal(PG_CATALOG.TEXT, anyelement, anyelement) RENAME TO datediff_internal_deprecated_3_4_0; +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'datediff_internal_deprecated_3_4_0'); + +ALTER FUNCTION sys.datediff_internal_df(PG_CATALOG.TEXT, anyelement, anyelement) RENAME TO datediff_internal_df_deprecated_in_3_4_0; +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'datediff_internal_df_deprecated_in_3_4_0'); + +ALTER FUNCTION sys.datediff_internal_date(PG_CATALOG.TEXT, PG_CATALOG.date, PG_CATALOG.date) RENAME TO datediff_internal_date_deprecated_in_3_4_0; +CALL sys.babelfish_drop_deprecated_object('function', 'sys', 'datediff_internal_date_deprecated_in_3_4_0'); + +CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdate PG_CATALOG.date, IN enddate PG_CATALOG.date) RETURNS INTEGER +AS +$body$ +BEGIN + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdate sys.datetime, IN enddate sys.datetime) RETURNS INTEGER +AS +$body$ +BEGIN + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdate sys.datetimeoffset, IN enddate sys.datetimeoffset) RETURNS INTEGER +AS +$body$ +BEGIN + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdate sys.datetime2, IN enddate sys.datetime2) RETURNS INTEGER +AS +$body$ +BEGIN + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdate sys.smalldatetime, IN enddate sys.smalldatetime) RETURNS INTEGER +AS +$body$ +BEGIN + return sys.datediff_internal(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff(IN datepart PG_CATALOG.TEXT, IN startdate PG_CATALOG.time, IN enddate PG_CATALOG.time) RETURNS INTEGER +AS +$body$ +BEGIN + return sys.datediff_internal(datepart, startdate, enddate); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +-- datediff big +CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN startdate PG_CATALOG.date, IN enddate PG_CATALOG.date) RETURNS BIGINT +AS +$body$ +BEGIN + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN startdate sys.datetime, IN enddate sys.datetime) RETURNS BIGINT +AS +$body$ +BEGIN + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN startdate sys.datetimeoffset, IN enddate sys.datetimeoffset) RETURNS BIGINT +AS +$body$ +BEGIN + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN startdate sys.datetime2, IN enddate sys.datetime2) RETURNS BIGINT +AS +$body$ +BEGIN + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN startdate sys.smalldatetime, IN enddate sys.smalldatetime) RETURNS BIGINT +AS +$body$ +BEGIN + return sys.datediff_internal_big(datepart, startdate::TIMESTAMP, enddate::TIMESTAMP); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.datediff_big(IN datepart PG_CATALOG.TEXT, IN startdate PG_CATALOG.time, IN enddate PG_CATALOG.time) RETURNS BIGINT +AS +$body$ +BEGIN + return sys.datediff_internal_big(datepart, startdate, enddate); +END +$body$ +LANGUAGE plpgsql IMMUTABLE; + + +/* + This function is needed when input date is datetimeoffset type. When running the following query in postgres using tsql dialect, it faied. + 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 +'babelfishpg_common', 'dateadd_datetimeoffset' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.dateadd_internal(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT) RETURNS ANYELEMENT AS $$ +BEGIN + IF pg_typeof(startdate) = 'time'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 0); + END IF; + IF pg_typeof(startdate) = 'date'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 1); + END IF; + IF pg_typeof(startdate) = 'sys.smalldatetime'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 2); + END IF; + IF (pg_typeof(startdate) = 'sys.datetime'::regtype or pg_typeof(startdate) = 'timestamp'::regtype) THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 3); + END IF; + IF pg_typeof(startdate) = 'sys.datetime2'::regtype THEN + return sys.dateadd_internal_datetime(datepart, num, startdate, 4); + END IF; +END; +$$ +STRICT +LANGUAGE plpgsql IMMUTABLE; + +CREATE OR REPLACE FUNCTION sys.dateadd_internal_datetime(IN datepart PG_CATALOG.TEXT, IN num INTEGER, IN startdate ANYELEMENT, IN datetimetype INT) +RETURNS TIMESTAMP AS +'babelfishpg_common', 'dateadd_datetime' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datediff_internal_big(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) +RETURNS BIGINT AS +'babelfishpg_common', 'timestamp_diff_big' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE OR REPLACE FUNCTION sys.datediff_internal(IN datepart PG_CATALOG.TEXT, IN startdate anyelement, IN enddate anyelement) +RETURNS INT AS +'babelfishpg_common', 'timestamp_diff' +STRICT +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +-- 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); + +-- After upgrade, always run analyze for all babelfish catalogs. +CALL sys.analyze_babelfish_catalogs(); + +-- 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/upgrades/babelfishpg_tsql--3.4.0--3.5.0.sql b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.4.0--3.5.0.sql new file mode 100644 index 0000000000..7b1076d53a --- /dev/null +++ b/contrib/babelfishpg_tsql/sql/upgrades/babelfishpg_tsql--3.4.0--3.5.0.sql @@ -0,0 +1,49 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ""babelfishpg_tsql"" UPDATE TO '3.4.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; + +-- Please add your SQLs here +/* + * Note: These SQL statements may get executed multiple times specially when some features get backpatched. + * So make sure that any SQL statement (DDL/DML) being added here can be executed multiple times without affecting + * final behaviour. + */ + +-- 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); + +-- After upgrade, always run analyze for all babelfish catalogs. +CALL sys.analyze_babelfish_catalogs(); + +-- 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/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..d27676f062 100644 --- a/contrib/babelfishpg_tsql/src/babelfish_version.h +++ b/contrib/babelfishpg_tsql/src/babelfish_version.h @@ -8,8 +8,7 @@ *------------------------------------------------------------------------- */ -#define BABELFISH_VERSION_STR "3.2.0" -#define BABELFISH_INTERNAL_VERSION_STR "Babelfish 15.3.0.0" +#define BABELFISH_VERSION_STR "3.5.0" +#define BABELFISH_INTERNAL_VERSION_STR "Babelfish 15.6.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-decl.y b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y index c414483b55..dc249d8a46 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-decl.y @@ -72,7 +72,8 @@ %type datepart_arg datediff_arg dateadd_arg %type tsql_type_function_name %type tsql_createproc_args tsql_createfunc_args -%type tsql_triggername +%type tsql_triggername tsql_trigger_list +%type tsql_enable_disable_trigger %type tsql_top_clause opt_top_clause @@ -93,9 +94,12 @@ %type tsql_output_target_el %type tsql_alter_server_role +%type tsql_contains_search_condition +%type tsql_pivot_expr + %token TSQL_ATAT TSQL_ALLOW_SNAPSHOT_ISOLATION TSQL_CALLER TSQL_CHOOSE TSQL_CLUSTERED TSQL_COLUMNSTORE TSQL_CONVERT - TSQL_DATENAME TSQL_DATEPART TSQL_DATEDIFF TSQL_DATEDIFF_BIG TSQL_DATEADD TSQL_DEFAULT_SCHEMA TSQL_ISNULL + TSQL_DATENAME TSQL_DATEPART TSQL_DATETRUNC TSQL_DATEDIFF TSQL_DATEDIFF_BIG TSQL_DATE_BUCKET TSQL_DATEADD TSQL_DEFAULT_SCHEMA TSQL_ISNULL TSQL_D TSQL_DAYOFYEAR TSQL_DD TSQL_DW TSQL_DY TSQL_HH TSQL_ISO_WEEK TSQL_ISOWK TSQL_ISOWW TSQL_LOGIN TSQL_M TSQL_MCS TSQL_MI TSQL_MICROSECOND TSQL_MILLISECOND TSQL_MM TSQL_MS TSQL_N TSQL_NANOSECOND TSQL_NONCLUSTERED TSQL_NS TSQL_OUTPUT TSQL_OUT TSQL_PARSE TSQL_Q @@ -107,14 +111,15 @@ 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 TSQL_MUST_CHANGE TSQL_CHECK_EXPIRATION TSQL_CHECK_POLICY TSQL_CREDENTIAL TSQL_SID TSQL_OLD_PASSWORD TSQL_UNLOCK TSQL_VALUES TSQL_NVARCHAR - TSQL_CROSS TSQL_OUTER TSQL_APPLY + TSQL_CROSS TSQL_OUTER TSQL_APPLY TSQL_PIVOT + TSQL_CONTAINS TSQL_FREETEXT /* * WITH_paren is added to support table hints syntax WITH ( [[,]...n]), 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..9c9d49b0e5 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; + 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); - /* For handling try boolean logic on babelfishpg_tsql side */ - Node *try_const = makeBoolAConst(try, location); - if (style) + 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,33 +193,70 @@ 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); - else if (strcmp(typename_string, "varchar") == 0) + result = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_conv_helper_to_datetime"), args, COERCE_EXPLICIT_CALL, location); + + else if ((strcmp(typename_string, "varchar") == 0) || (strcmp(typename_string, "nvarchar") == 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; +} +Node * +TsqlFunctionIdentityInto(TypeName *typename, Node *seed, Node *increment, int location) +{ + Node *result; + List *args; + int32 typmod; + Oid type_oid; + Oid base_oid; + typenameTypeIdAndMod(NULL, typename, &type_oid, &typmod); + base_oid = getBaseType(type_oid); + switch (base_oid) + { + case INT2OID: + case INT4OID: + args = list_make3((Node *)makeIntConst((int)type_oid, location), seed, increment); + break; + case INT8OID: + case NUMERICOID: + args = list_make3((Node *)makeIntConst((int)INT8OID, location), seed, increment); /* Used bigint internally for decimal and numeric as well*/ + break; + default: + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Parameter or variable '' has an invalid data type."))); + break; + } + result = (Node *)makeFuncCall(TsqlSystemFuncName("identity_into_bigint"), args, COERCE_EXPLICIT_CALL, location); return result; } @@ -226,39 +269,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 +318,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 +411,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 +438,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 +459,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,126 +532,253 @@ 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) +{ + 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) +{ + if (pg_strcasecmp(typenameStr, "nvarchar") == 0) + { + return true; + } + else if (pg_strcasecmp(typenameStr, "sys.nvarchar") == 0) + { + return true; + } + return false; +} + +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; + } +} + +/* + * 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; + 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)) + { + 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); + return (Node *) fc; } -bool isCharType(char* typenameStr) +bool +is_json_query(List *name) { - 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; + 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; + } } -bool isNVarCharType(char* typenameStr) +/* +* Parse T-SQL CONTAINS predicate. Currently only supports +* ... CONTAINS(column_name, '') ... +* This function transform it into a Postgres AST that stands for +* to_tsvector(pgconfig, column_name) @@ to_tsquery(pgconfig, babelfish_fts_rewrite('')) +* where pgconfig = babelfish_fts_contains_pgconfig('') +*/ +static Node * +TsqlExpressionContains(char *colId, Node *search_expr, core_yyscan_t yyscanner) { - if(pg_strcasecmp(typenameStr, "nvarchar") == 0) - { - return true; - } - else if(pg_strcasecmp(typenameStr, "sys.nvarchar") == 0) - { - return true; - } - return false; + A_Expr *fts; + Node *to_tsvector_call, *to_tsquery_call; + Node *result_pgconfig; + List *args_pgconfig; + + args_pgconfig = list_make1(search_expr); + result_pgconfig = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_fts_contains_pgconfig"), args_pgconfig, COERCE_EXPLICIT_CALL, -1); + + to_tsvector_call = makeToTSVectorFuncCall(colId, yyscanner, result_pgconfig); + to_tsquery_call = makeToTSQueryFuncCall(search_expr, result_pgconfig); + + fts = makeA_Expr(AEXPR_OP, list_make1(makeString("@@")), to_tsvector_call, to_tsquery_call, -1); + + return (Node *)fts; +} + +/* Transform column_name into to_tsvector(pgconfig, column_name) */ +static Node * +makeToTSVectorFuncCall(char *colId, core_yyscan_t yyscanner, Node *pgconfig) +{ + Node *col; + List *args; + + col = makeColumnRef(colId, NIL, -1, yyscanner); + + args = list_make2(pgconfig, col); + + return (Node *) makeFuncCall(list_make1(makeString("to_tsvector")), args, COERCE_EXPLICIT_CALL, -1); } -int getElemTypMod(TypeName *t) +/* Transfrom '' into to_tsquery(pgconfig, babelfish_fts_rewrite('')) */ +static Node * +makeToTSQueryFuncCall(Node *search_expr, Node *pgconfig) { - 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 *args; + Node *result_rewrite; + List *args_rewrite; + + args_rewrite = list_make1(search_expr); + result_rewrite = (Node *) makeFuncCall(TsqlSystemFuncName("babelfish_fts_rewrite"), args_rewrite, COERCE_EXPLICIT_CALL, -1); + + + args = list_make2(pgconfig, result_rewrite); + return (Node *) makeFuncCall(list_make1(makeString("to_tsquery")), args, COERCE_EXPLICIT_CALL, -1); } + /* * helper macro to compare relname in * function tsql_update_delete_stmt_with_join @@ -604,53 +793,54 @@ int getElemTypMod(TypeName *t) 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; @@ -658,29 +848,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 = where_clause; + n_d->limitCount = top_clause; + 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 = where_clause; + n_u->limitCount = top_clause; + return (Node *) n_u; } } /* construct select statment->target */ @@ -688,15 +879,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); @@ -708,82 +899,24 @@ 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; - } -} - -/* - * Similar to JOIN, we rewrite TOP clause into a subquery, while attaching the - * TOP as a LIMIT in the subquery, for UPDATE/DELETE. - * - * original query: - * UPDATE/DELETE - * - * rewritten query: - * UPDATE/DELETE
WHERE ctid IN (SELECT ctid FROM
) - */ -static Node * -tsql_update_delete_stmt_with_top(Node *top_clause, RangeVar *relation, Node - *where_clause, core_yyscan_t yyscanner) -{ - SubLink * link; - List* indirect; - SelectStmt *selectstmt; - ResTarget *resTarget; - - if (top_clause == NULL) - return where_clause; - - /* construct select statment->target */ - resTarget = makeNode(ResTarget); - resTarget->name = NULL; - resTarget->indirection = NIL; - indirect = list_make1((Node *) makeString("ctid")); - if(relation->alias) - { - resTarget->val = makeColumnRef(relation->alias->aliasname, - indirect,-1,yyscanner); + n_u->whereClause = (Node *) link; + return (Node *) n_u; } - else - { - resTarget->val = makeColumnRef(relation->relname, - indirect,-1,yyscanner); - } - - /* construct select statement */ - selectstmt = makeNode(SelectStmt); - selectstmt->targetList = list_make1(resTarget); - selectstmt->fromClause = list_make1(relation); - selectstmt->whereClause = where_clause; - selectstmt->limitCount = top_clause; - - /* construct where_clause(subLink) */ - link = makeNode(SubLink); - link->subselect = (Node*)selectstmt; - link->subLinkType = ANY_SUBLINK; - link->subLinkId = 0; - link->testexpr = (Node*)makeColumnRef(pstrdup("ctid"), - NIL, -1, yyscanner);; - link->operName = NIL; /* show it's IN not = ANY */ - link->location = -1; - - return (Node *)link; } /* @@ -791,29 +924,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; @@ -822,102 +956,124 @@ 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; } } +/* + * Resets the state of two global vars used for UPDATE and DELETE queries + * + * In some cases, an erroring UPDATE query can exit without resetting these + * globals. This function is called before UPDATE and DELETE statements that + * use these globals to ensure that they are cleared. + */ +static void +tsql_reset_update_delete_globals() +{ + output_update_transformation = false; + update_delete_target_alias = NULL; +} + 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, 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) { - + 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->limitCount = opt_top_clause; i->relation = insert_target; i->onConflictClause = NULL; i->returningList = get_transformed_output_list(tsql_output_clause); 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 @@ -927,31 +1083,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; @@ -960,17 +1118,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 { @@ -980,74 +1138,77 @@ 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 + + tsql_reset_update_delete_globals(); + + /* 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); - output_update_transformation = true; + d = (DeleteStmt *) tsql_update_delete_stmt_with_join( + (Node *) d, from_clause, where_or_current_clause, opt_top_clause, + relation_expr_opt_alias, yyscanner); } 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); - if (from_clause != NULL && (IsA(linitial(from_clause), RangeSubselect) || IsA(linitial(from_clause), RangeVar))) - output_update_transformation = true; + d->whereClause = where_or_current_clause; + d->limitCount = opt_top_clause; } 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); @@ -1055,9 +1216,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 @@ -1067,47 +1228,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 { @@ -1122,21 +1285,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; @@ -1149,76 +1314,83 @@ 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 + + tsql_reset_update_delete_globals(); + + /* 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 { u->fromClause = from_clause; u->whereClause = where_or_current_clause; + u->limitCount = opt_top_clause; } u->returningList = get_transformed_output_list(tsql_output_clause); 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 @@ -1226,9 +1398,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 @@ -1238,47 +1410,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 { @@ -1289,84 +1463,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; @@ -1378,27 +1563,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); } @@ -1409,22 +1595,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; @@ -1438,28 +1625,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)) { @@ -1476,15 +1664,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), @@ -1492,14 +1681,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); @@ -1516,28 +1707,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)) { @@ -1553,18 +1745,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), @@ -1572,11 +1767,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); @@ -1591,7 +1788,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 @@ -1601,7 +1798,110 @@ 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; } + +/* pivot select transformation*/ +static Node * +tsql_pivot_select_transformation(List *target_list, List *from_clause, List *pivot_clause, Alias *alias_clause, SelectStmt *pivot_sl) +{ + FuncCall *pivotCall; + ColumnRef *a_star; + ResTarget *a_star_restarget; + RangeFunction *funCallNode; + SelectStmt *src_sql; + SortBy *s; + + char *pivot_colstr = (char *)list_nth(pivot_clause, 0); + Node *aggFunc = (Node *) list_nth(pivot_clause, 1); + + /* prepare SortBy node for source sql */ + s = makeNode(SortBy); + s->node = makeIntConst(1, -1); + s->sortby_dir = 0; + s->sortby_nulls = 0; + s->useOp = NIL; + s->location = -1; + + /* transform to select * from funcCall as newtable(a type1, b type2 ...) */ + a_star = makeNode(ColumnRef); + a_star->fields = list_make1(makeNode(A_Star)); + a_star->location = -1; + a_star_restarget = makeNode(ResTarget); + a_star_restarget->name = NULL; + a_star_restarget->name_location = -1; + a_star_restarget->indirection = NIL; + a_star_restarget->val = (Node *) a_star; + a_star_restarget->location = -1; + + /* prepare source sql for babelfish_pivot function */ + src_sql = makeNode(SelectStmt); + src_sql->targetList = list_make1(a_star_restarget); + src_sql->fromClause = from_clause; + src_sql->sortClause = list_make1(s); + + /* create a function call node for the fromClause */ + pivotCall = makeFuncCall(TsqlSystemFuncName2("bbf_pivot"),NIL, COERCE_EXPLICIT_CALL, -1); + funCallNode = makeNode(RangeFunction); + funCallNode->lateral = false; + funCallNode->is_rowsfrom = false; + funCallNode->functions = list_make1(list_make2((Node *) pivotCall, NIL)); + funCallNode->alias = alias_clause; + + pivot_sl->targetList = target_list; + pivot_sl->fromClause = list_make1(funCallNode); + pivot_sl->isPivot = true; + pivot_sl->srcSql = src_sql; + pivot_sl->catSql = list_nth((List *)pivot_clause, 2); + pivot_sl->pivotCol = pivot_colstr; + pivot_sl->aggFunc = aggFunc; + pivot_sl->value_col_strlist = (List *) list_nth((List *)pivot_clause, 3); + + return (Node *)pivot_sl; +} + +/* + * Adjust index nulls order to match SQL Server behavior. + * For ASC (or unspecified) index, default should be NULLS FIRST; + * for DESC index, default should be NULLS LAST. + */ +static void +tsql_index_nulls_order(List *indexParams, const char *accessMethod) +{ + ListCell *lc; + + foreach(lc, indexParams) + { + Node *n = lfirst(lc); + IndexElem *indexElem; + + if (!IsA(n, IndexElem)) + continue; + + indexElem = (IndexElem *) n; + + /* No need to adjust if user already specified the nulls order */ + if (indexElem->nulls_ordering != SORTBY_NULLS_DEFAULT) + continue; + + /* GIN indexes don't support NULLS FIRST/LAST options */ + if (strcmp(accessMethod, "gin") == 0) + return; + + switch (indexElem->ordering) + { + case SORTBY_ASC: + case SORTBY_DEFAULT: + indexElem->nulls_ordering = SORTBY_NULLS_FIRST; + break; + case SORTBY_DESC: + indexElem->nulls_ordering = SORTBY_NULLS_LAST; + break; + default: + break; + } + } +} 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..5f8256de59 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 @@ -9,6 +9,7 @@ #include "parser/parse_type.h" #include "parser/scansup.h" #include "utils/builtins.h" +#include "utils/lsyscache.h" #include "common/md5.h" #include "src/backend_parser/gramparse.h" @@ -18,17 +19,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; @@ -44,39 +45,47 @@ static Node *TsqlFunctionConvert(TypeName *typename, Node *arg, Node *style, boo static Node *TsqlFunctionParse(Node *arg, TypeName *typename, Node *culture, bool try, int location); static Node *TsqlFunctionIIF(Node *bool_expr, Node *arg1, Node *arg2, int location); +static Node *TsqlFunctionIdentityInto(TypeName *typename, Node *seed, Node *increment, 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 *tsql_pivot_select_transformation(List *target_list, List *from_clause, List *pivot_clause, Alias *alias_clause, SelectStmt *pivot_sl); -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); -char * construct_unique_index_name(char *index_name, char *relation_name); +static Node *TsqlJsonModifyMakeFuncCall(Node *expr, Node *path, Node *newValue); +static bool is_json_query(List *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_top(Node *top_clause, RangeVar - *relation, Node *where_clause, core_yyscan_t yyscanner); +static Node *TsqlExpressionContains(char *colId, Node *search_expr, core_yyscan_t yyscanner); +static Node *makeToTSVectorFuncCall(char *colId, core_yyscan_t yyscanner, Node *pgconfig); +static Node *makeToTSQueryFuncCall(Node *search_expr, Node *pgconfig); + +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 void tsql_reset_update_delete_globals(void); 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, 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, - 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); +static void tsql_index_nulls_order(List *indexParams, const char *accessMethod); 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..98bc9d16d6 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y +++ b/contrib/babelfishpg_tsql/src/backend_parser/gram-tsql-rule.y @@ -417,6 +417,17 @@ tsql_alter_user_options: (Node *)makeString($3), @1); } + | TSQL_LOGIN '=' RoleId + { + RoleSpec *login = makeRoleSpec(ROLESPEC_CSTRING, @1); + List *rolelist; + + login->rolename = pstrdup($3); + rolelist = list_make1(login); + $$ = makeDefElem("rolemembers", + (Node *)rolelist, + @1); + } ; tsql_AlterLoginStmt: @@ -464,6 +475,72 @@ tsql_AlterLoginStmt: } ; +tsql_enable_disable_trigger: + tsql_enable_disable TRIGGER tsql_trigger_list ON relation_expr + { + AlterTableCmd *n1; + AlterTableStmt *n2 = makeNode(AlterTableStmt); + ListCell *lc; + + foreach(lc, $3) + { + List *lst = lfirst_node(List, lc); + n1 = makeNode(AlterTableCmd); + + if ($1) + { + n1->subtype = AT_EnableTrig; + } + else + { + n1->subtype = AT_DisableTrig; + } + + if (list_length(lst) > 1) + { + n1->schemaname = strVal(list_nth(lst,0)); + n1->name = strVal(list_nth(lst,1)); + } + else + { + n1->name = strVal(list_nth(lst,0)); + } + n2->cmds = list_concat(n2->cmds, list_make1((Node *) n1)); + } + + n2->relation = $5; + + n2->objtype = OBJECT_TRIGGER; + n2->missing_ok = false; + $$ = (Node *)n2; + } + | tsql_enable_disable TRIGGER ALL ON relation_expr + { + AlterTableCmd *n1 = makeNode(AlterTableCmd); + AlterTableStmt *n2 = makeNode(AlterTableStmt); + + if ($1) + { + n1->subtype = AT_EnableTrigAll; + } + else + { + n1->subtype = AT_DisableTrigAll; + } + + n2->relation = $5; + n2->cmds = list_make1((Node *) n1); + n2->objtype = OBJECT_TRIGGER; + n2->missing_ok = false; + $$ = (Node *)n2; + } + ; + +tsql_trigger_list: + tsql_triggername { $$ = list_make1($1); } + | tsql_trigger_list ',' tsql_triggername { $$ = lappend($1, $3); } + ; + tsql_enable_disable: ENABLE_P { @@ -1207,38 +1284,7 @@ DeleteStmt: opt_with_clause DELETE_P FROM relation_expr_opt_alias } ; -tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias - SET set_clause_list - from_clause - where_or_current_clause - returning_clause - { - UpdateStmt *n = makeNode(UpdateStmt); - n->relation = $3; - n->targetList = $5; - n->fromClause = $6; - n->whereClause = $7; - n->returningList = $8; - n->withClause = $1; - $$ = (Node *)n; - } - | opt_with_clause UPDATE relation_expr_opt_alias - tsql_table_hint_expr - SET set_clause_list - from_clause - where_or_current_clause - returning_clause - { - UpdateStmt *n = makeNode(UpdateStmt); - n->relation = $3; - n->targetList = $6; - n->fromClause = $7; - n->whereClause = $8; - n->returningList = $9; - n->withClause = $1; - $$ = (Node *)n; - } - | opt_with_clause UPDATE tsql_top_clause relation_expr_opt_alias +tsql_UpdateStmt: opt_with_clause UPDATE opt_top_clause relation_expr_opt_alias tsql_opt_table_hint_expr SET set_clause_list from_clause @@ -1246,73 +1292,18 @@ tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias returning_clause { UpdateStmt *n = makeNode(UpdateStmt); + tsql_reset_update_delete_globals(); + n->withClause = $1; + n->limitCount = $3; n->relation = $4; - tsql_update_delete_stmt_from_clause_alias(n->relation, $8); 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; } /* OUTPUT syntax */ - | opt_with_clause UPDATE relation_expr_opt_alias - SET set_clause_list - tsql_output_clause - from_clause - where_or_current_clause - { - UpdateStmt *n = makeNode(UpdateStmt); - n->relation = $3; - tsql_update_delete_stmt_from_clause_alias(n->relation, $7); - n->targetList = $5; - if ($7 != NULL && IsA(linitial($7), JoinExpr)) - { - n = (UpdateStmt*)tsql_update_delete_stmt_with_join( - (Node*)n, $7, $8, NULL, $3, - yyscanner); - - } - else - { - n->fromClause = $7; - n->whereClause = $8; - } - tsql_check_update_output_transformation($6); - n->returningList = $6; - n->withClause = $1; - $$ = (Node *)n; - } - | opt_with_clause UPDATE relation_expr_opt_alias - tsql_table_hint_expr - SET set_clause_list - tsql_output_clause - from_clause - where_or_current_clause - { - UpdateStmt *n = makeNode(UpdateStmt); - n->relation = $3; - tsql_update_delete_stmt_from_clause_alias(n->relation, - $8); - n->targetList = $6; - n->fromClause = $8; - n->whereClause = $9; - tsql_check_update_output_transformation($7); - n->returningList = $7; - n->withClause = $1; - $$ = (Node *)n; - } - | opt_with_clause UPDATE tsql_top_clause relation_expr_opt_alias + | opt_with_clause UPDATE opt_top_clause relation_expr_opt_alias tsql_opt_table_hint_expr SET set_clause_list tsql_output_clause @@ -1320,11 +1311,11 @@ tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias where_or_current_clause { UpdateStmt *n = makeNode(UpdateStmt); + tsql_reset_update_delete_globals(); n->relation = $4; - tsql_update_delete_stmt_from_clause_alias(n->relation, - $8); + tsql_update_delete_stmt_from_clause_alias(n->relation, $9); n->targetList = $7; - if ($8 != NULL && IsA(linitial($8), JoinExpr)) + if ($9 != NULL && IsA(linitial($9), JoinExpr)) { n = (UpdateStmt*)tsql_update_delete_stmt_with_join( (Node*)n, $9, $10, $3, $4, @@ -1332,9 +1323,9 @@ tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias } else { - n->fromClause = $8; - n->whereClause = tsql_update_delete_stmt_with_top($3, - $4, $10, yyscanner); + n->limitCount = $3; + n->fromClause = $9; + n->whereClause = $10; } tsql_check_update_output_transformation($8); n->returningList = $8; @@ -1342,26 +1333,7 @@ tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias $$ = (Node *)n; } /* OUTPUT INTO syntax with OUTPUT target column list */ - | opt_with_clause UPDATE relation_expr_opt_alias - SET set_clause_list - tsql_output_clause INTO insert_target tsql_output_into_target_columns - from_clause - where_or_current_clause - { - $$ = tsql_update_output_into_cte_transformation($1, NULL, $3, $5, $6, $8, - $9, $10, $11, yyscanner); - } - | opt_with_clause UPDATE relation_expr_opt_alias - tsql_table_hint_expr - SET set_clause_list - tsql_output_clause INTO insert_target tsql_output_into_target_columns - from_clause - where_or_current_clause - { - $$ = tsql_update_output_into_cte_transformation($1, NULL, $3, $6, $7, $9, - $10, $11, $12, yyscanner); - } - | opt_with_clause UPDATE tsql_top_clause relation_expr_opt_alias + | opt_with_clause UPDATE opt_top_clause relation_expr_opt_alias tsql_opt_table_hint_expr SET set_clause_list tsql_output_clause INTO insert_target tsql_output_into_target_columns @@ -1372,26 +1344,7 @@ tsql_UpdateStmt: opt_with_clause UPDATE relation_expr_opt_alias $11, $12, $13, yyscanner); } /* Without OUTPUT target column list */ - | opt_with_clause UPDATE relation_expr_opt_alias - SET set_clause_list - tsql_output_clause INTO insert_target - from_clause - where_or_current_clause - { - $$ = tsql_update_output_into_cte_transformation($1, NULL, $3, $5, $6, $8, - NIL, $9, $10, yyscanner); - } - | opt_with_clause UPDATE relation_expr_opt_alias - tsql_table_hint_expr - SET set_clause_list - tsql_output_clause INTO insert_target - from_clause - where_or_current_clause - { - $$ = tsql_update_output_into_cte_transformation($1, NULL, $3, $6, $7, $9, - NIL, $10, $11, yyscanner); - } - | opt_with_clause UPDATE tsql_top_clause relation_expr_opt_alias + | opt_with_clause UPDATE opt_top_clause relation_expr_opt_alias tsql_opt_table_hint_expr SET set_clause_list tsql_output_clause INTO insert_target @@ -1542,6 +1495,7 @@ simple_select: n->groupDistinct = ($8)->distinct; n->havingClause = $9; n->windowClause = $10; + n->isPivot = false; $$ = (Node *)n; } | SELECT distinct_clause tsql_top_clause target_list @@ -1566,11 +1520,157 @@ simple_select: n->groupDistinct = ($8)->distinct; n->havingClause = $9; n->windowClause = $10; + n->isPivot = false; $$ = (Node *)n; } + | SELECT opt_all_clause tsql_top_clause opt_target_list + into_clause from_clause tsql_pivot_expr alias_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->limitCount = $3; + if ($3 != NULL && $4 == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Target list missing from TOP clause"), + errhint("For example, TOP n COLUMNS ..."), + parser_errposition(@3))); + n->intoClause = $5; + n->whereClause = $9; + n->groupClause = ($10)->list; + n->groupDistinct = ($10)->distinct; + n->havingClause = $11; + n->windowClause = $12; + $$ = tsql_pivot_select_transformation($4, $6, (List *)$7, $8, n); + } + | SELECT distinct_clause tsql_top_clause target_list + into_clause from_clause tsql_pivot_expr alias_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->limitCount = $3; + if ($3 != NULL && $4 == NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Target list missing from TOP clause"), + errhint("For example, TOP n COLUMNS ..."), + parser_errposition(@3))); + n->intoClause = $5; + n->whereClause = $9; + n->groupClause = ($10)->list; + n->groupDistinct = ($10)->distinct; + n->havingClause = $11; + n->windowClause = $12; + $$ = tsql_pivot_select_transformation($4, $6, (List *)$7, $8, n); + } + | SELECT opt_all_clause opt_target_list + into_clause from_clause tsql_pivot_expr alias_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->intoClause = $4; + n->whereClause = $8; + n->groupClause = ($9)->list; + n->groupDistinct = ($9)->distinct; + n->havingClause = $10; + n->windowClause = $11; + $$ = tsql_pivot_select_transformation($3, $5, (List *)$6, $7, n); + } + | SELECT distinct_clause target_list + into_clause from_clause tsql_pivot_expr alias_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->intoClause = $4; + n->whereClause = $8; + n->groupClause = ($9)->list; + n->groupDistinct = ($9)->distinct; + n->havingClause = $10; + n->windowClause = $11; + $$ = tsql_pivot_select_transformation($3, $5, (List *)$6, $7, n); + } | tsql_values_clause { $$ = $1; } ; +tsql_pivot_expr: TSQL_PIVOT '(' func_application FOR ColId IN_P in_expr ')' + { + ColumnRef *a_star; + ResTarget *a_star_restarget; + RangeSubselect *range_sub_select; + Alias *temptable_alias; + SortBy *s; + List *ret; + List *value_col_strlist = NULL; + List *subsel_valuelists = NULL; + + SelectStmt *category_sql = makeNode(SelectStmt); + SelectStmt *valuelists_sql = makeNode(SelectStmt); + ResTarget *restarget_aggfunc = makeNode(ResTarget); + + a_star = makeNode(ColumnRef); + a_star->fields = list_make1(makeNode(A_Star)); + a_star->location = -1; + a_star_restarget = makeNode(ResTarget); + a_star_restarget->name = NULL; + a_star_restarget->name_location = -1; + a_star_restarget->indirection = NIL; + a_star_restarget->val = (Node *) a_star; + a_star_restarget->location = -1; + + + /* prepare aggregation function for pivot source sql */ + restarget_aggfunc->name = NULL; + restarget_aggfunc->name_location = -1; + restarget_aggfunc->indirection = NIL; + restarget_aggfunc->val = (Node *) $3; + restarget_aggfunc->location = -1; + + if (IsA((List *)$7, List)) + { + for (int i = 0; i < ((List *)$7)->length; i++) + { + ColumnRef *tempRef = list_nth((List *)$7, i); + String *s = list_nth(tempRef->fields, 0); + Node *n = makeStringConst(s->sval, -1); + List *l = list_make1(copyObject(n)); + if (value_col_strlist == NULL || subsel_valuelists == NULL) + { + value_col_strlist = list_make1(s->sval); + subsel_valuelists = list_make1(l); + }else + { + value_col_strlist = lappend(value_col_strlist, s->sval); + subsel_valuelists = lappend(subsel_valuelists, l); + } + } + } + + temptable_alias = makeNode(Alias); + temptable_alias->aliasname = "pivotTempTable"; + temptable_alias->colnames = list_make1(makeString(pstrdup($5))); + + valuelists_sql->valuesLists = subsel_valuelists; + + range_sub_select = makeNode(RangeSubselect); + range_sub_select->subquery = (Node *) valuelists_sql; + range_sub_select->alias = temptable_alias; + + s = makeNode(SortBy); + s->node = makeIntConst(1, -1); + s->sortby_dir = 0; + s->sortby_nulls = 0; + s->useOp = NIL; + s->location = -1; + + category_sql->targetList = list_make1(a_star_restarget); + category_sql->fromClause = list_make1(range_sub_select); + category_sql->sortClause = list_make1(s); + + ret = list_make4(pstrdup($5), restarget_aggfunc, category_sql, value_col_strlist); + $$ = (Node*) ret; + } + ; + table_ref: relation_expr tsql_table_hint_expr { $$ = (Node *) $1; @@ -1848,6 +1948,20 @@ func_expr_common_subexpr: COERCE_EXPLICIT_CALL, @1); } + | TSQL_DATE_BUCKET '(' datediff_arg ',' a_expr ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("date_bucket"), + list_make3(makeStringConst($3, @3), $5, $7), + COERCE_EXPLICIT_CALL, + @1); + } + | TSQL_DATE_BUCKET '(' datediff_arg ',' a_expr ',' a_expr ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("date_bucket"), + list_make4(makeStringConst($3, @3), $5, $7, $9), + COERCE_EXPLICIT_CALL, + @1); + } | TSQL_DATEPART '(' datepart_arg ',' a_expr ')' { $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("datepart"), @@ -1855,6 +1969,13 @@ func_expr_common_subexpr: COERCE_EXPLICIT_CALL, @1); } + | TSQL_DATETRUNC '(' datepart_arg ',' a_expr ')' + { + $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("datetrunc"), + list_make2(makeStringConst($3, @3), $5), + COERCE_EXPLICIT_CALL, + @1); + } | TSQL_DATENAME '(' datepart_arg ',' a_expr ')' { $$ = (Node *) makeFuncCall(TsqlSystemFuncName2("datename"), @@ -1889,7 +2010,34 @@ 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); + } + | IDENTITY_P '(' Typename ',' a_expr ',' a_expr ')' + { + $$ = TsqlFunctionIdentityInto($3, $5, $7, @1); + } + | IDENTITY_P '(' Typename ',' a_expr ')' + { + $$ = TsqlFunctionIdentityInto($3, $5, (Node *)makeIntConst(1, -1), @1); + } + | IDENTITY_P '(' Typename ')' + { + $$ = TsqlFunctionIdentityInto($3, (Node *)makeIntConst(1, -1), (Node *)makeIntConst(1, -1), @1); + } + | TSQL_CONTAINS '(' ColId ',' tsql_contains_search_condition ')' + { + $$ = TsqlExpressionContains($3, $5, yyscanner); + } + ; + +tsql_contains_search_condition: + a_expr + { + $$ = $1; + } ; target_el: @@ -1940,8 +2088,14 @@ AexprConst: { /* This is to support N'str' in various locations */ TypeName *t = makeTypeNameFromNameList(list_make2(makeString("sys"), makeString("nvarchar"))); + /* Include a typmod based on the length of the literal */ + int32 typmod = strlen($2); + if (typmod == 0) + typmod = 2; /* typmod can't be 0 */ + else if (typmod > 4000) + typmod = TSQLMaxTypmod; t->location = @1; - t->typmods = list_make1(makeIntConst(TSQLMaxTypmod, -1)); + t->typmods = list_make1(makeIntConst(typmod, -1)); $$ = makeStringConstCast($2, @2, t); } ; @@ -2017,37 +2171,70 @@ tsql_output_insert_rest_no_paren: ; tsql_output_simple_select: - SELECT opt_all_clause opt_target_list + SELECT opt_all_clause opt_top_clause opt_target_list into_clause from_clause where_clause group_clause having_clause window_clause { SelectStmt *n = makeNode(SelectStmt); - n->targetList = $3; - n->intoClause = $4; - n->fromClause = $5; - n->whereClause = $6; - n->groupClause = ($7)->list; - n->groupDistinct = ($7)->distinct; - n->havingClause = $8; - n->windowClause = $9; + n->limitCount = $3; + n->targetList = $4; + n->intoClause = $5; + n->fromClause = $6; + n->whereClause = $7; + n->groupClause = ($8)->list; + n->groupDistinct = ($8)->distinct; + n->havingClause = $9; + n->windowClause = $10; + n->isPivot = false; $$ = (Node *)n; } - | SELECT distinct_clause target_list + | SELECT distinct_clause opt_top_clause target_list into_clause from_clause where_clause group_clause having_clause window_clause { SelectStmt *n = makeNode(SelectStmt); n->distinctClause = $2; - n->targetList = $3; - n->intoClause = $4; - n->fromClause = $5; - n->whereClause = $6; - n->groupClause = ($7)->list; - n->groupDistinct = ($7)->distinct; - n->havingClause = $8; - n->windowClause = $9; + n->limitCount = $3; + n->targetList = $4; + n->intoClause = $5; + n->fromClause = $6; + n->whereClause = $7; + n->groupClause = ($8)->list; + n->groupDistinct = ($8)->distinct; + n->havingClause = $9; + n->windowClause = $10; + n->isPivot = false; $$ = (Node *)n; } + | SELECT opt_all_clause opt_top_clause opt_target_list + into_clause from_clause tsql_pivot_expr alias_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->limitCount = $3; + n->intoClause = $5; + n->whereClause = $9; + n->groupClause = ($10)->list; + n->groupDistinct = ($10)->distinct; + n->havingClause = $11; + n->windowClause = $12; + $$ = tsql_pivot_select_transformation($4, $6, (List *)$7, $8, n); + } + | SELECT distinct_clause opt_top_clause target_list + into_clause from_clause tsql_pivot_expr alias_clause where_clause + group_clause having_clause window_clause + { + SelectStmt *n = makeNode(SelectStmt); + n->distinctClause = $2; + n->limitCount = $3; + n->intoClause = $5; + n->whereClause = $9; + n->groupClause = ($10)->list; + n->groupDistinct = ($10)->distinct; + n->havingClause = $11; + n->windowClause = $12; + $$ = tsql_pivot_select_transformation($4, $6, (List *)$7, $8, n); + } | tsql_values_clause { $$ = $1; } | tsql_output_simple_select UNION set_quantifier tsql_output_simple_select { @@ -2270,6 +2457,7 @@ tsql_stmt : | DropUserMappingStmt | tsql_DropRoleStmt | DropdbStmt + | tsql_enable_disable_trigger | tsql_ExecStmt | ExplainStmt | FetchStmt @@ -2315,29 +2503,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; @@ -2347,42 +2538,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; @@ -2391,27 +2585,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); @@ -2422,31 +2616,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); @@ -2457,7 +2651,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); } */ ; @@ -2996,6 +3190,8 @@ tsql_IndexStmt: n->initdeferred = false; n->transformed = false; n->if_not_exists = false; + + tsql_index_nulls_order(n->indexParams, n->accessMethod); $$ = (Node *)n; } ; @@ -3121,28 +3317,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; @@ -3152,20 +3330,11 @@ tsql_DeleteStmt: opt_with_clause DELETE_P opt_top_clause opt_from relation_expr_ tsql_opt_table_hint_expr tsql_output_clause from_clause where_or_current_clause { DeleteStmt *n = makeNode(DeleteStmt); + tsql_reset_update_delete_globals(); n->relation = $5; - tsql_update_delete_stmt_from_clause_alias(n->relation, $8); - if ($8 != NULL && IsA(linitial($8), JoinExpr)) - { - n = (DeleteStmt*)tsql_update_delete_stmt_with_join( - (Node*)n, $8, $9, $3, $5, - yyscanner); - } - else - { - n->usingClause = $8; - n->whereClause = tsql_update_delete_stmt_with_top($3, - $5, $9, yyscanner); - } + n->limitCount = $3; + n->usingClause = $8; + n->whereClause = $9; n->returningList = $7; n->withClause = $1; $$ = (Node *)n; @@ -3616,12 +3785,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 @@ -4231,11 +4406,20 @@ tsql_IsolationLevelStr: } | REPEATABLE READ { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_REPEATABLE_READ); - ereport(ERROR, + if (pltsql_isolation_level_repeatable_read) + { + TSQLInstrumentation(INSTR_TSQL_ISOLATION_LEVEL_REPEATABLE_READ); + $$ = "repeatable read"; + } + else + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_REPEATABLE_READ); + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("REPEATABLE READ isolation level is not supported"), + errmsg("Isolation level ‘REPEATABLE READ’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_repeatable_read’ config option to get PG repeatable read isolation level."), parser_errposition(@1))); + } + } | SNAPSHOT { @@ -4244,11 +4428,19 @@ tsql_IsolationLevelStr: } | SERIALIZABLE { - TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_SERIALIZABLE); - ereport(ERROR, + if (pltsql_isolation_level_serializable) + { + TSQLInstrumentation(INSTR_TSQL_ISOLATION_LEVEL_SERIALIZABLE); + $$ = "serializable"; + } + else + { + TSQLInstrumentation(INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_SERIALIZABLE); + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("SERIALIZABLE isolation level is not supported"), + errmsg("Isolation level ‘SERIALIZABLE’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_serializable’ config option to get PG serializable isolation level."), parser_errposition(@1))); + } } ; @@ -4261,6 +4453,7 @@ createdb_opt_item: col_name_keyword: TSQL_NVARCHAR | OPENJSON + | JSON_MODIFY ; unreserved_keyword: @@ -4361,8 +4554,10 @@ reserved_keyword: | TSQL_DATEADD | TSQL_DATEDIFF | TSQL_DATEDIFF_BIG + | TSQL_DATE_BUCKET | TSQL_DATENAME | TSQL_DATEPART + | TSQL_DATETRUNC | TSQL_IIF | TSQL_OUT | TSQL_OUTER @@ -4377,6 +4572,10 @@ reserved_keyword: | TSQL_EXEC ; +bare_label_keyword: + TSQL_CONTAINS + ; + privilege: UPDATE_paren '(' columnList ')' { 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/kwlist.h b/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h index 3aad82df71..601d2a1d6e 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h +++ b/contrib/babelfishpg_tsql/src/backend_parser/kwlist.h @@ -86,6 +86,7 @@ PG_KEYWORD("conflict", CONFLICT, UNRESERVED_KEYWORD) PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD) PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD) PG_KEYWORD("constraints", CONSTRAINTS, UNRESERVED_KEYWORD) +PG_KEYWORD("contains", TSQL_CONTAINS, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("content", CONTENT_P, UNRESERVED_KEYWORD) PG_KEYWORD("continue", CONTINUE_P, UNRESERVED_KEYWORD) PG_KEYWORD("conversion", CONVERSION_P, UNRESERVED_KEYWORD) @@ -110,11 +111,13 @@ PG_KEYWORD("cycle", CYCLE, UNRESERVED_KEYWORD) PG_KEYWORD("d", TSQL_D, UNRESERVED_KEYWORD) PG_KEYWORD("data", DATA_P, UNRESERVED_KEYWORD) PG_KEYWORD("database", DATABASE, UNRESERVED_KEYWORD) +PG_KEYWORD("date_bucket", TSQL_DATE_BUCKET, RESERVED_KEYWORD) PG_KEYWORD("dateadd", TSQL_DATEADD, RESERVED_KEYWORD) PG_KEYWORD("datediff", TSQL_DATEDIFF, RESERVED_KEYWORD) PG_KEYWORD("datediff_big", TSQL_DATEDIFF_BIG, RESERVED_KEYWORD) PG_KEYWORD("datename", TSQL_DATENAME, RESERVED_KEYWORD) PG_KEYWORD("datepart", TSQL_DATEPART, RESERVED_KEYWORD) +PG_KEYWORD("datetrunc", TSQL_DATETRUNC, RESERVED_KEYWORD) PG_KEYWORD("day", DAY_P, UNRESERVED_KEYWORD) PG_KEYWORD("dayofyear", TSQL_DAYOFYEAR, UNRESERVED_KEYWORD) PG_KEYWORD("dd", TSQL_DD, UNRESERVED_KEYWORD) @@ -239,6 +242,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) @@ -344,6 +348,7 @@ PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD) PG_KEYWORD("path", TSQL_PATH, UNRESERVED_KEYWORD) PG_KEYWORD("percent", TSQL_PERCENT, RESERVED_KEYWORD) PG_KEYWORD("persisted", TSQL_PERSISTED, UNRESERVED_KEYWORD) +PG_KEYWORD("pivot", TSQL_PIVOT, RESERVED_KEYWORD) PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD) PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD) PG_KEYWORD("policy", POLICY, UNRESERVED_KEYWORD) 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..696b42e85e 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,12 +74,12 @@ 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) { - pgtsql_core_yyfree(ptr, yyscanner); + core_yyfree(ptr, yyscanner); } #define core_yyset_extra pgtsql_core_yyset_extra 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/scan-tsql-rule.l b/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-rule.l index e256e3fffd..38ea5a6aa6 100644 --- a/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-rule.l +++ b/contrib/babelfishpg_tsql/src/backend_parser/scan-tsql-rule.l @@ -215,8 +215,10 @@ case TSQL_DATEADD: case TSQL_DATEDIFF: case TSQL_DATEDIFF_BIG: + case TSQL_DATE_BUCKET: case TSQL_DATENAME: case TSQL_DATEPART: + case TSQL_DATETRUNC: case TSQL_D: case TSQL_DAYOFYEAR: case TSQL_DD: 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 5354521ee1..8f1f9bdc2a 100644 --- a/contrib/babelfishpg_tsql/src/catalog.c +++ b/contrib/babelfishpg_tsql/src/catalog.c @@ -11,12 +11,14 @@ #include "catalog/pg_namespace.h" #include "catalog/pg_authid.h" #include "catalog/pg_proc.h" +#include "catalog/pg_foreign_server.h" #include "catalog/namespace.h" #include "parser/parse_relation.h" #include "parser/scansup.h" #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" @@ -35,21 +37,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 @@ -69,18 +71,36 @@ Oid bbf_authid_user_ext_idx_oid; Oid bbf_view_def_oid; Oid bbf_view_def_idx_oid; +/***************************************** + * LINKED_SERVERS_DEF + *****************************************/ +Oid bbf_servers_def_oid; +Oid bbf_servers_def_idx_oid; + /***************************************** * FUNCTION_EXT *****************************************/ Oid bbf_function_ext_oid; Oid bbf_function_ext_idx_oid; +/***************************************** + * SCHEMA + *****************************************/ +Oid bbf_schema_perms_oid; +Oid bbf_schema_perms_idx_oid; + /***************************************** * DOMAIN MAPPING *****************************************/ Oid bbf_domain_mapping_oid = InvalidOid; Oid bbf_domain_mapping_idx_oid = InvalidOid; +/***************************************** + * EXTENDED_PROPERTIES + *****************************************/ +Oid bbf_extended_properties_oid = InvalidOid; +Oid bbf_extended_properties_idx_oid = InvalidOid; + /***************************************** * Catalog General *****************************************/ @@ -90,49 +110,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_sysdatabases_oid, + 0, + 0, + 0 + }, + 16 + }, + {-1, /* SYSDATABASENAME */ + -1, + 1, + { + Anum_sysdatabases_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); @@ -170,16 +191,23 @@ Datum init_catalog(PG_FUNCTION_ARGS) bbf_view_def_oid = get_relname_relid(BBF_VIEW_DEF_TABLE_NAME, sys_schema_oid); bbf_view_def_idx_oid = get_relname_relid(BBF_VIEW_DEF_IDX_NAME, sys_schema_oid); + /* bbf_servers_def */ + bbf_servers_def_oid = get_relname_relid(BBF_SERVERS_DEF_TABLE_NAME, sys_schema_oid); + bbf_servers_def_idx_oid = get_relname_relid(BBF_SERVERS_DEF_IDX_NAME, sys_schema_oid); + if (sysdatabases_oid != InvalidOid) initTsqlSyscache(); 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; } @@ -189,77 +217,121 @@ 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; } +bool +IsPltsqlToastRelationHook(Relation relation) +{ + /* + * If relname is pg_toast and exists in ENR then it is a local toast relation. + * Match IsToastRelation() such that return true for locally owned toast relation only. + */ + if (strstr(RelationGetRelationName(relation), "@pg_toast")) + return get_ENR(currentQueryEnv, RelationGetRelationName(relation)); + + return IsToastNamespace(RelationGetNamespace(relation)); +} + +bool IsPltsqlToastClassHook(Form_pg_class pg_class_tup) +{ + /* + * Similar as above but different input parameter + */ + char *relname = NameStr((pg_class_tup)->relname); + if (strstr(relname, "@pg_toast")) + return get_ENR(currentQueryEnv, relname); + + return IsToastNamespace(pg_class_tup->relnamespace); +} + +void pltsql_drop_relation_refcnt_hook(Relation relation) +{ + int expected_refcnt = 0; + if (sql_dialect != SQL_DIALECT_TSQL || + !RelationIsBBFTableVariable(relation)) + return; + + expected_refcnt = relation->rd_isnailed ? 2 : 1; + + while (relation->rd_refcnt > expected_refcnt) + { + RelationDecrementReferenceCount(relation); + } +} + /***************************************** * 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_sysdatabases_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_sysdatabases_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))) @@ -269,7 +341,7 @@ const char *get_one_user_db_name(void) } tuple = heap_getnext(scan, ForwardScanDirection); } - + table_endscan(scan); table_close(rel, AccessShareLock); @@ -282,78 +354,90 @@ PG_FUNCTION_INFO_V1(babelfish_helpdb); Datum babelfish_helpdb(PG_FUNCTION_ARGS) { - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - char *dbname; - 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); - - - /* 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); 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))); + (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)); + Anum_sysdatabases_name, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(dbname_lower)); scan = systable_beginscan(rel, sysdatabaese_idx_name_oid, true, - NULL, 1, &scanKey); + NULL, 1, &scanKey); } else { @@ -361,30 +445,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)); + db_name_entry = TextDatumGetCString(heap_getattr(tuple, Anum_sysdatabases_name, + RelationGetDescr(rel), &isNull)); values[0] = CStringGetTextDatum(db_name_entry); - nulls[1] = 1; + nulls[1] = 1; values[2] = CStringGetTextDatum(NameStr(sysdb->owner)); @@ -395,29 +479,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)); + tmstmp = DatumGetTimestamp(heap_getattr(tuple, Anum_sysdatabases_crdate, + RelationGetDescr(rel), &isNull)); tmstmp_str = OidOutputFunctionCall(datetime_output_func, tmstmp); values[4] = CStringGetTextDatum(tmstmp_str); - nulls[5] = 1; - nulls[6] = 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(); } /***************************************** @@ -427,16 +511,16 @@ 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) + if (get_namespace_oid(physical_schema_name, missingOk) == InvalidOid) return NULL; rel = table_open(namespace_ext_oid, AccessShareLock); @@ -457,8 +541,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); @@ -472,10 +556,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; @@ -502,8 +586,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); @@ -523,8 +607,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; @@ -533,7 +617,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); @@ -565,10 +649,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); @@ -595,10 +679,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); @@ -611,20 +696,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, @@ -642,17 +727,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; } @@ -686,18 +771,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); @@ -728,9 +813,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; @@ -748,19 +832,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); @@ -784,7 +868,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); @@ -818,12 +902,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; @@ -866,12 +950,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; @@ -895,8 +979,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, @@ -914,11 +998,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; @@ -936,7 +1020,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); @@ -960,9 +1044,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); @@ -970,14 +1054,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 @@ -985,8 +1072,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; @@ -1020,11 +1107,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; @@ -1034,14 +1122,14 @@ search_bbf_view_def(Relation bbf_view_def_rel, int16 dbid, const char *logical_s BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); - ScanKeyInit(&scanKey[1], - Anum_bbf_view_def_schema_name, - BTEqualStrategyNumber, F_TEXTEQ, + ScanKeyEntryInitialize(&scanKey[1], 0, Anum_bbf_view_def_schema_name, + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), F_TEXTEQ, CStringGetTextDatum(logical_schema_name)); - ScanKeyInit(&scanKey[2], - Anum_bbf_view_def_object_name, - BTEqualStrategyNumber, F_TEXTEQ, + ScanKeyEntryInitialize(&scanKey[2], 0, Anum_bbf_view_def_object_name, + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), F_TEXTEQ, CStringGetTextDatum(view_name)); scan = systable_beginscan(bbf_view_def_rel, @@ -1058,12 +1146,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); @@ -1107,10 +1196,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); @@ -1129,13 +1218,88 @@ clean_up_bbf_view_def(int16 dbid) { if (HeapTupleIsValid(scantup)) CatalogTupleDelete(bbf_view_def_rel, - &scantup->t_self); + &scantup->t_self); } systable_endscan(scan); table_close(bbf_view_def_rel, RowExclusiveLock); } +/***************************************** + * LINKED_SERVERS_DEF + *****************************************/ + +Oid +get_bbf_servers_def_oid() +{ + if (!OidIsValid(bbf_servers_def_oid)) + bbf_servers_def_oid = get_relname_relid(BBF_SERVERS_DEF_TABLE_NAME, + get_namespace_oid("sys", false)); + + return bbf_servers_def_oid; +} + +Oid +get_bbf_servers_def_idx_oid() +{ + if (!OidIsValid(bbf_servers_def_idx_oid)) + bbf_servers_def_idx_oid = get_relname_relid(BBF_SERVERS_DEF_IDX_NAME, + get_namespace_oid("sys", false)); + + return bbf_servers_def_idx_oid; +} + +int +get_timeout_from_server_name(char *servername, int attnum) +{ + Relation bbf_servers_def_rel; + HeapTuple tuple; + ScanKeyData key; + TableScanDesc scan; + int timeout = 0; + + bbf_servers_def_rel = table_open(get_bbf_servers_def_oid(), + RowExclusiveLock); + + ScanKeyInit(&key, + Anum_bbf_servers_def_servername, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(servername)); + + scan = table_beginscan_catalog(bbf_servers_def_rel, 1, &key); + + tuple = heap_getnext(scan, ForwardScanDirection); + if (HeapTupleIsValid(tuple)) + { + bool isNull; + timeout = DatumGetInt32(heap_getattr(tuple, attnum, + RelationGetDescr(bbf_servers_def_rel), &isNull)); + if (isNull) + timeout = 0; + } + + table_endscan(scan); + table_close(bbf_servers_def_rel, RowExclusiveLock); + return timeout; +} + +void +clean_up_bbf_server_def() +{ + char *query_str; + StringInfoData query; + + initStringInfo(&query); + + appendStringInfo(&query, "TRUNCATE TABLE sys.babelfish_server_options CASCADE"); + + query_str = query.data; + + exec_utility_cmd_helper(query_str); + + pfree(query.data); +} + /***************************************** * FUNCTION_EXT *****************************************/ @@ -1145,7 +1309,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; } @@ -1155,7 +1319,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; } @@ -1163,14 +1327,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; @@ -1179,8 +1343,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 */ @@ -1213,11 +1377,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); @@ -1225,12 +1390,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)); @@ -1243,7 +1408,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, @@ -1264,7 +1429,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); @@ -1276,6 +1441,29 @@ clean_up_bbf_function_ext(int16 dbid) table_close(bbf_function_ext_rel, RowExclusiveLock); } + +/***************************************** + * SCHEMA + *****************************************/ + +Oid +get_bbf_schema_perms_oid() +{ + if (!OidIsValid(bbf_schema_perms_oid)) + bbf_schema_perms_oid = get_relname_relid(BBF_SCHEMA_PERMS_TABLE_NAME, + get_namespace_oid("sys", false)); + return bbf_schema_perms_oid; +} + +Oid +get_bbf_schema_perms_idx_oid() +{ + if (!OidIsValid(bbf_schema_perms_idx_oid)) + bbf_schema_perms_idx_oid = get_relname_relid(BBF_SCHEMA_PERMS_IDX_NAME, + get_namespace_oid("sys", false)); + return bbf_schema_perms_idx_oid; +} + /***************************************** * DOMAIN MAPPING *****************************************/ @@ -1285,7 +1473,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; } @@ -1295,11 +1483,35 @@ 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; } +/***************************************** + * EXTENDED_PROPERTIES + *****************************************/ + +Oid +get_bbf_extended_properties_oid() +{ + if (!OidIsValid(bbf_extended_properties_oid)) + bbf_extended_properties_oid = get_relname_relid(BBF_EXTENDED_PROPERTIES_TABLE_NAME, + get_namespace_oid("sys", false)); + + return bbf_extended_properties_oid; +} + +Oid +get_bbf_extended_properties_idx_oid() +{ + if (!OidIsValid(bbf_extended_properties_idx_oid)) + bbf_extended_properties_idx_oid = get_relname_relid(BBF_EXTENDED_PROPERTIES_IDX_NAME, + get_namespace_oid("sys", false)); + + return bbf_extended_properties_idx_oid; +} + /***************************************** * Metadata Check * --------------------------------------- @@ -1308,19 +1520,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); @@ -1345,21 +1559,27 @@ 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); +static Datum get_server_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); +static void alter_guest_schema_for_db(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); @@ -1367,119 +1587,128 @@ 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_sysdatabases", InvalidOid, InvalidOid, true, InvalidOid, Anum_sysdatabases_name, F_TEXTEQ}, {"babelfish_namespace_ext", InvalidOid, InvalidOid, true, InvalidOid, Anum_namespace_ext_namespace, F_NAMEEQ}, {"babelfish_authid_login_ext", InvalidOid, InvalidOid, true, InvalidOid, Anum_bbf_authid_login_ext_rolname, F_NAMEEQ}, {"babelfish_authid_user_ext", InvalidOid, InvalidOid, true, InvalidOid, Anum_bbf_authid_user_ext_rolname, F_NAMEEQ}, {"pg_namespace", InvalidOid, InvalidOid, true, InvalidOid, Anum_pg_namespace_nspname, F_NAMEEQ}, {"pg_authid", InvalidOid, InvalidOid, true, InvalidOid, Anum_pg_authid_rolname, F_NAMEEQ}, - {"pg_proc", InvalidOid, InvalidOid, false, InvalidOid, Anum_pg_proc_proname, F_NAMEEQ} + {"pg_proc", InvalidOid, InvalidOid, false, InvalidOid, Anum_pg_proc_proname, F_NAMEEQ}, + {"pg_foreign_server", InvalidOid, InvalidOid, true, InvalidOid, Anum_pg_foreign_server_srvname, 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} }; - + + +/* babelfish_server_options */ +Rule must_match_rules_srv_options[] = +{ + {" in babelfish_server_options must also exist in pg_foreign_server", + "pg_foreign_server", "srvname", NULL, get_server_name, NULL, check_exist, NULL} +}; + /***************************************** * Core function *****************************************/ @@ -1494,51 +1723,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); @@ -1563,31 +1792,32 @@ 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]); + size_t num_must_match_rules_srv_options = sizeof(must_match_rules_srv_options) / sizeof(must_match_rules_srv_options[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)) @@ -1597,11 +1827,14 @@ 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)) - ) + || + !(check_must_match_rules(must_match_rules_srv_options, num_must_match_rules_srv_options, + bbf_servers_def_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. @@ -1613,7 +1846,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) ()) @@ -1651,25 +1884,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))) @@ -1686,9 +1919,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(); @@ -1720,7 +1953,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); } @@ -1777,6 +2011,7 @@ static Datum get_owner(HeapTuple tuple, TupleDesc dsc) { Form_sysdatabases sysdb = ((Form_sysdatabases) GETSTRUCT(tuple)); + return NameGetDatum(&(sysdb->owner)); } @@ -1785,8 +2020,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); @@ -1799,8 +2034,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); @@ -1813,8 +2048,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); @@ -1825,8 +2060,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; } @@ -1834,6 +2070,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)); } @@ -1841,6 +2078,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)); } @@ -1848,14 +2086,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; } @@ -1863,6 +2103,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)); } @@ -1870,9 +2111,20 @@ static Datum get_function_name(HeapTuple tuple, TupleDesc dsc) { Form_bbf_function_ext func = ((Form_bbf_function_ext) GETSTRUCT(tuple)); + return NameGetDatum(&(func->funcname)); } +static Datum +get_server_name(HeapTuple tuple, TupleDesc dsc) +{ + Form_bbf_servers_def srv_def = ((Form_bbf_servers_def) GETSTRUCT(tuple)); + const text *srv_name = &(srv_def->servername); + char *servername = text_to_cstring(srv_name); + + return CStringGetDatum(servername); +} + /***************************************** * Condition check funcs *****************************************/ @@ -1896,12 +2148,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; @@ -1916,10 +2168,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); @@ -1937,17 +2189,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))); @@ -1985,7 +2237,7 @@ init_catalog_data(void) { catalog_data[i].tbl_oid = sysdatabases_oid; catalog_data[i].idx_oid = sysdatabaese_idx_name_oid; - catalog_data[i].atttype = get_atttype(sysdatabases_oid, Anum_sysdatabaese_name); + catalog_data[i].atttype = get_atttype(sysdatabases_oid, Anum_sysdatabases_name); } else if (strcmp(catalog_data[i].tblname, "babelfish_namespace_ext") == 0) { @@ -2023,6 +2275,12 @@ init_catalog_data(void) catalog_data[i].idx_oid = InvalidOid; catalog_data[i].atttype = get_atttype(ProcedureRelationId, Anum_pg_proc_proname); } + else if (strcmp(catalog_data[i].tblname, "pg_foreign_server") == 0) + { + catalog_data[i].tbl_oid = ForeignServerRelationId; + catalog_data[i].idx_oid = ForeignServerNameIndexId; + catalog_data[i].atttype = get_atttype(ForeignServerRelationId, Anum_pg_foreign_server_srvname); + } else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -2033,8 +2291,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++) { @@ -2047,7 +2305,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))); } @@ -2058,21 +2316,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, @@ -2094,9 +2352,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 @@ -2122,11 +2383,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); @@ -2155,12 +2416,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); @@ -2168,14 +2430,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_sysdatabases_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)) { @@ -2193,16 +2454,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, @@ -2228,18 +2489,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; "); @@ -2254,6 +2515,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; @@ -2268,7 +2530,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(); { @@ -2290,11 +2552,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(); @@ -2325,9 +2587,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); @@ -2344,10 +2606,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); @@ -2358,7 +2621,7 @@ void rename_update_bbf_catalog(RenameStmt *stmt) { switch (stmt->renameType) - { + { case OBJECT_TABLE: break; case OBJECT_VIEW: @@ -2372,69 +2635,71 @@ rename_update_bbf_catalog(RenameStmt *stmt) break; case OBJECT_SEQUENCE: break; + case OBJECT_TRIGGER: + break; + case OBJECT_TYPE: + break; + case OBJECT_COLUMN: + 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 - 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); + /* 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] = {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; - // get the description of the table + /* open the catalog table */ + bbf_view_def_rel = table_open(get_bbf_view_def_oid(), RowExclusiveLock); + /* 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, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(dbid)); logical_schema_name = get_logical_schema_name(stmt->relation->schemaname, true); - ScanKeyInit(&key[1], - Anum_bbf_view_def_schema_name, - BTEqualStrategyNumber, F_TEXTEQ, - CStringGetTextDatum(logical_schema_name)); - ScanKeyInit(&key[2], + ScanKeyEntryInitialize(&key[1], 0, Anum_bbf_view_def_schema_name, + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, CStringGetTextDatum(logical_schema_name)); + ScanKeyEntryInitialize(&key[2], 0, Anum_bbf_view_def_object_name, - BTEqualStrategyNumber, F_TEXTEQ, - CStringGetTextDatum(stmt->relation->relname)); + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), + 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; @@ -2455,47 +2720,46 @@ 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 - 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 + /* + * 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] = {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; + StringInfoData new_funcsign; + Datum funcsign_datum; + Node *schema; + char *schemaname; + ObjectWithArgs *objwargs = (ObjectWithArgs *) stmt->object; + + /* 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], @@ -2503,32 +2767,39 @@ 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)); - 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, @@ -2536,20 +2807,519 @@ 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)) + { + orig_proc_funcname = NULL; 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); + orig_proc_funcname = NULL; heap_freetuple(new_tuple); table_endscan(tblscan); table_close(bbf_func_ext_rel, RowExclusiveLock); -} \ No newline at end of file +} + +/* Add a catalog entry. */ +void +add_entry_to_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee, + const char *object_type) +{ + Relation bbf_schema_rel; + TupleDesc bbf_schema_dsc; + HeapTuple tuple_bbf_schema; + Datum new_record_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + bool new_record_nulls_bbf_schema[BBF_SCHEMA_PERMS_NUM_OF_COLS]; + int16 dbid = get_cur_db_id(); + + /* Fetch the relation */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + bbf_schema_dsc = RelationGetDescr(bbf_schema_rel); + + /* Build a tuple to insert */ + MemSet(new_record_bbf_schema, 0, sizeof(new_record_bbf_schema)); + MemSet(new_record_nulls_bbf_schema, false, sizeof(new_record_nulls_bbf_schema)); + + new_record_bbf_schema[BBF_SCHEMA_PERMS_DBID] = Int16GetDatum(dbid); + new_record_bbf_schema[BBF_SCHEMA_PERMS_SCHEMA_NAME] = CStringGetDatum(pstrdup(schema_name)); + new_record_bbf_schema[BBF_SCHEMA_PERMS_OBJECT_NAME] = CStringGetDatum(pstrdup(object_name)); + new_record_bbf_schema[BBF_SCHEMA_PERMS_PERMISSION] = CStringGetDatum(pstrdup(permission)); + new_record_bbf_schema[BBF_SCHEMA_PERMS_GRANTEE] = CStringGetDatum(pstrdup(grantee)); + if (object_type != NULL) + new_record_bbf_schema[BBF_SCHEMA_PERMS_OBJECT_TYPE] = CStringGetDatum(pstrdup(object_type)); + else + new_record_nulls_bbf_schema[BBF_SCHEMA_PERMS_OBJECT_TYPE] = true; + + tuple_bbf_schema = heap_form_tuple(bbf_schema_dsc, + new_record_bbf_schema, + new_record_nulls_bbf_schema); + + /* Insert new record in the bbf_authid_user_ext table */ + CatalogTupleInsert(bbf_schema_rel, tuple_bbf_schema); + + /* Close bbf_authid_user_ext, but keep lock till commit */ + table_close(bbf_schema_rel, RowExclusiveLock); + + /* Advance cmd counter to make the insert visible */ + CommandCounterIncrement(); +} + +/* Check if the catalog entry exists. */ +bool +check_bbf_schema_for_entry(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData key[5]; + TableScanDesc scan; + bool catalog_entry_exists = false; + int16 dbid = get_cur_db_id(); + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + ScanKeyInit(&key[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&key[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&key[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyInit(&key[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyInit(&key[4], + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = table_beginscan_catalog(bbf_schema_rel, 5, key); + + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + if (HeapTupleIsValid(tuple_bbf_schema)) + catalog_entry_exists = true; + + table_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); + return catalog_entry_exists; +} + +bool +check_bbf_schema_for_schema(const char *schema_name, + const char *object_name, + const char *permission) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData key[4]; + TableScanDesc scan; + bool catalog_entry_exists = false; + int16 dbid = get_cur_db_id(); + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + ScanKeyInit(&key[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&key[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&key[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyInit(&key[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + + scan = table_beginscan_catalog(bbf_schema_rel, 4, key); + + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + if (HeapTupleIsValid(tuple_bbf_schema)) + catalog_entry_exists = true; + + table_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); + return catalog_entry_exists; +} + +void +del_from_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee) +{ + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + ScanKeyData key[5]; + TableScanDesc scan; + int16 dbid = get_cur_db_id(); + + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + ScanKeyInit(&key[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&key[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&key[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + ScanKeyInit(&key[3], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyInit(&key[4], + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = table_beginscan_catalog(bbf_schema_rel, 5, key); + + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + + if (HeapTupleIsValid(tuple_bbf_schema)) + CatalogTupleDelete(bbf_schema_rel, &tuple_bbf_schema->t_self); + + table_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); + + CommandCounterIncrement(); +} + +void +clean_up_bbf_schema(const char *schema_name, + const char *object_name, + bool is_schema) +{ + SysScanDesc scan; + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + int16 dbid = get_cur_db_id(); + + /* Fetch the relation */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + RowExclusiveLock); + + if (is_schema) + { + ScanKeyData scanKey[2]; + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&scanKey[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 2, scanKey); + } + else + { + ScanKeyData scanKey[3]; + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&scanKey[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&scanKey[2], + Anum_bbf_schema_perms_object_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(object_name)); + scan = systable_beginscan(bbf_schema_rel, + get_bbf_schema_perms_idx_oid(), + true, NULL, 3, scanKey); + } + + while ((tuple_bbf_schema = systable_getnext(scan)) != NULL) + { + if (HeapTupleIsValid(tuple_bbf_schema)) + CatalogTupleDelete(bbf_schema_rel, + &tuple_bbf_schema->t_self); + } + + systable_endscan(scan); + table_close(bbf_schema_rel, RowExclusiveLock); +} + +void +grant_perms_to_objects_in_schema(const char *schema_name, + const char *permission, + const char *grantee) +{ + TableScanDesc scan; + Relation bbf_schema_rel; + HeapTuple tuple_bbf_schema; + const char *object_name; + const char *object_type; + ScanKeyData scanKey[4]; + int16 dbid = get_cur_db_id(); + const char *db_name = get_cur_db_name(); + + /* Fetch the relation */ + bbf_schema_rel = table_open(get_bbf_schema_perms_oid(), + AccessShareLock); + ScanKeyInit(&scanKey[0], + Anum_bbf_schema_perms_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(dbid)); + ScanKeyInit(&scanKey[1], + Anum_bbf_schema_perms_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + ScanKeyInit(&scanKey[2], + Anum_bbf_schema_perms_permission, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(permission)); + ScanKeyInit(&scanKey[3], + Anum_bbf_schema_perms_grantee, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(grantee)); + + scan = table_beginscan_catalog(bbf_schema_rel, 4, scanKey); + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + + while (HeapTupleIsValid(tuple_bbf_schema)) + { + Form_bbf_schema_perms schemaform; + schemaform = (Form_bbf_schema_perms) GETSTRUCT(tuple_bbf_schema); + object_name = pstrdup(NameStr(schemaform->object_name)); + object_type = pstrdup(NameStr(schemaform->object_type)); + + /* For each object, grant the permission explicitly. */ + if (strcmp(object_name, "ALL") != 0) + { + StringInfoData query; + char *schema; + List *res; + Node *res_stmt; + PlannedStmt *wrapper; + + schema = get_physical_schema_name((char *)db_name, schema_name); + initStringInfo(&query); + if (strcmp(permission, "execute") != 0) + appendStringInfo(&query, "GRANT \"%s\" ON \"%s\".\"%s\" TO \"%s\"; ", permission, schema, object_name, grantee); + else + { + if (object_type != NULL && strcmp(object_type, "f") == 0) + appendStringInfo(&query, "GRANT \"%s\" ON FUNCTION \"%s\".\"%s\" TO \"%s\"; ", permission, schema, object_name, grantee); + else + appendStringInfo(&query, "GRANT \"%s\" ON PROCEDURE \"%s\".\"%s\" TO \"%s\"; ", permission, schema, object_name, grantee); + } + res = raw_parser(query.data, RAW_PARSE_DEFAULT); + res_stmt = ((RawStmt *) linitial(res))->stmt; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = res_stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = 1; + + /* do this step */ + ProcessUtility(wrapper, + "(GRANT STATEMENT )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + } + tuple_bbf_schema = heap_getnext(scan, ForwardScanDirection); + } + table_endscan(scan); + table_close(bbf_schema_rel, AccessShareLock); +} + +PG_FUNCTION_INFO_V1(update_user_catalog_for_guest_schema); +Datum +update_user_catalog_for_guest_schema(PG_FUNCTION_ARGS) +{ + 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); + tuple = heap_getnext(scan, ForwardScanDirection); + + while (HeapTupleIsValid(tuple)) + { + Datum db_name_datum = heap_getattr(tuple, Anum_sysdatabases_name, + db_rel->rd_att, &is_null); + const char *db_name = TextDatumGetCString(db_name_datum); + + alter_guest_schema_for_db(db_name); + tuple = heap_getnext(scan, ForwardScanDirection); + } + table_endscan(scan); + table_close(db_rel, AccessShareLock); + PG_RETURN_INT32(0); +} + +static void +alter_guest_schema_for_db (const char *dbname) +{ + 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 */ + ScanKeyInit(&key[0], + Anum_bbf_authid_user_ext_orig_username, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum("guest")); + ScanKeyInit(&key[1], + Anum_bbf_authid_user_ext_database_name, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(dbname)); + + tblscan = table_beginscan_catalog(bbf_authid_user_ext_rel, 2, key); + + /* Build a tuple to insert */ + MemSet(new_record_user_ext, 0, sizeof(new_record_user_ext)); + MemSet(new_record_nulls_user_ext, false, sizeof(new_record_nulls_user_ext)); + MemSet(new_record_repl_user_ext, false, sizeof(new_record_repl_user_ext)); + + usertuple = heap_getnext(tblscan, ForwardScanDirection); + if (!HeapTupleIsValid(usertuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Cannot find the user \"guest\", because it does not exist or you do not have permission."))); + + new_record_user_ext[USER_EXT_DEFAULT_SCHEMA_NAME] = CStringGetTextDatum("guest"); + new_record_repl_user_ext[USER_EXT_DEFAULT_SCHEMA_NAME] = true; + new_tuple = heap_modify_tuple(usertuple, + bbf_authid_user_ext_dsc, + new_record_user_ext, + new_record_nulls_user_ext, + new_record_repl_user_ext); + + CatalogTupleUpdate(bbf_authid_user_ext_rel, &new_tuple->t_self, new_tuple); + + heap_freetuple(new_tuple); + + table_endscan(tblscan); + table_close(bbf_authid_user_ext_rel, RowExclusiveLock); +} + +/* + * Update the owner of a database in the catalog. + */ +void +update_db_owner(const char *new_owner_name, const char *db_name) +{ + volatile Relation sysdatabases_rel; + TupleDesc sysdatabases_rel_descr; + ScanKeyData key; + HeapTuple tuple, db_found; + TableScanDesc tblscan; + + Datum values[SYSDATABASES_NUM_COLS]; + bool nulls[SYSDATABASES_NUM_COLS]; + bool replaces[SYSDATABASES_NUM_COLS]; + + /* Do not allow changes to system databases. */ + /* Note: T-SQL allows changing ownership of msdb. */ + if ( (strlen(db_name) == 6 && (strncmp(db_name, "master", 6) == 0)) || + (strlen(db_name) == 6 && (strncmp(db_name, "tempdb", 6) == 0)) + ) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Cannot change the owner of the master, model, tempdb or distribution database."))); + } + + /* Find the database */ + sysdatabases_rel = table_open(sysdatabases_oid, RowExclusiveLock); + sysdatabases_rel_descr = RelationGetDescr(sysdatabases_rel); + + ScanKeyInit(&key, + Anum_sysdatabases_name, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(db_name)); + + tblscan = table_beginscan_catalog(sysdatabases_rel, 1, &key); + + db_found = heap_getnext(tblscan, ForwardScanDirection); + + if (!db_found) + { + /* Database should have been verified to exist, but if not, exit politely */ + table_close(sysdatabases_rel, RowExclusiveLock); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", db_name))); + } + + /* Build a tuple */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + /* Set up the new owner. */ + values[Anum_sysdatabases_owner - 1] = CStringGetDatum(new_owner_name); + replaces[Anum_sysdatabases_owner - 1] = true; + + tuple = heap_modify_tuple(db_found, + sysdatabases_rel_descr, + values, + nulls, + replaces); + + /* Perform the actual catalog update. */ + CatalogTupleUpdate(sysdatabases_rel, &tuple->t_self, tuple); + + /* Cleanup. */ + heap_freetuple(tuple); + table_endscan(tblscan); + table_close(sysdatabases_rel, RowExclusiveLock); +} diff --git a/contrib/babelfishpg_tsql/src/catalog.h b/contrib/babelfishpg_tsql/src/catalog.h index 1370eb49bb..7b8ad195c2 100644 --- a/contrib/babelfishpg_tsql/src/catalog.h +++ b/contrib/babelfishpg_tsql/src/catalog.h @@ -18,11 +18,14 @@ extern void rename_update_bbf_catalog(RenameStmt *stmt); * Catalog Hooks *****************************************/ extern bool IsPLtsqlExtendedCatalog(Oid relationId); +extern bool IsPltsqlToastRelationHook(Relation relation); +extern bool IsPltsqlToastClassHook(Form_pg_class pg_class_tup); +extern void pltsql_drop_relation_refcnt_hook(Relation relation); /***************************************** * SYS schema *****************************************/ -extern Oid sys_schema_oid; +extern Oid sys_schema_oid; /***************************************** * SYSDATABASES @@ -31,24 +34,25 @@ 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 -#define Anum_sysdatabaese_oid 1 -#define Anum_sysdatabaese_name 6 -#define Anum_sysdatabaese_crdate 7 +#define Anum_sysdatabases_oid 1 +#define Anum_sysdatabases_owner 4 +#define Anum_sysdatabases_name 6 +#define Anum_sysdatabases_crdate 7 /* 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 +63,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 +100,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 +116,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,24 +136,25 @@ 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); extern char *get_user_for_database(const char *db_name); extern void alter_user_can_connect(bool is_grant, char *user_name, char *db_name); extern bool guest_role_exists_for_db(const char *dbname); +extern void update_db_owner(const char *new_owner_name, const char *db_name); /* 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 +162,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 +187,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 +207,36 @@ 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; + +/***************************************** + * LINKED_SERVERS_DEF + *****************************************/ +#define BBF_SERVERS_DEF_TABLE_NAME "babelfish_server_options" +#define BBF_SERVERS_DEF_IDX_NAME "babelfish_server_options_pkey" +#define Anum_bbf_servers_def_servername 1 +#define Anum_bbf_servers_def_query_timeout 2 +#define Anum_bbf_servers_def_connect_timeout 3 +#define BBF_SERVERS_DEF_NUM_COLS 3 +extern Oid bbf_servers_def_oid; +extern Oid bbf_servers_def_idx_oid; + +extern Oid get_bbf_servers_def_oid(void); +extern Oid get_bbf_servers_def_idx_oid(void); +extern int get_timeout_from_server_name(char *servername, int attnum); +extern int get_server_id_from_server_name(char *servername); +extern void clean_up_bbf_server_def(void); + +typedef struct FormData_bbf_servers_def +{ + text servername; + int32 query_timeout; + int32 connect_timeout; +} FormData_bbf_servers_def; -typedef FormData_bbf_view_def *Form_bbf_view_def; +typedef FormData_bbf_servers_def *Form_bbf_servers_def; /***************************************** * FUNCTION_EXT @@ -224,11 +256,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); @@ -248,6 +280,71 @@ typedef struct FormData_bbf_function_ext typedef FormData_bbf_function_ext *Form_bbf_function_ext; +/***************************************** + * SCHEMA_PERMISSIONS + *****************************************/ +#define BBF_SCHEMA_PERMS_TABLE_NAME "babelfish_schema_permissions" +#define BBF_SCHEMA_PERMS_IDX_NAME "babelfish_schema_permissions_pkey" +#define BBF_SCHEMA_PERMS_NUM_OF_COLS 6 +#define BBF_SCHEMA_PERMS_DBID 0 +#define BBF_SCHEMA_PERMS_SCHEMA_NAME 1 +#define BBF_SCHEMA_PERMS_OBJECT_NAME 2 +#define BBF_SCHEMA_PERMS_PERMISSION 3 +#define BBF_SCHEMA_PERMS_GRANTEE 4 +#define BBF_SCHEMA_PERMS_OBJECT_TYPE 5 +#define Anum_bbf_schema_perms_dbid 1 +#define Anum_bbf_schema_perms_schema_name 2 +#define Anum_bbf_schema_perms_object_name 3 +#define Anum_bbf_schema_perms_permission 4 +#define Anum_bbf_schema_perms_grantee 5 +#define Anum_bbf_schema_perms_object_type 6 + +extern Oid bbf_schema_perms_oid; +extern Oid bbf_schema_perms_idx_oid; + +extern Oid get_bbf_schema_perms_oid(void); +extern Oid get_bbf_schema_perms_idx_oid(void); + +typedef struct FormData_bbf_schema_perms +{ + int16 dbid; + NameData schema_name; + NameData object_name; + NameData permission; + NameData grantee; + NameData object_type; +} FormData_bbf_schema_perms; + +typedef FormData_bbf_schema_perms *Form_bbf_schema_perms; + +extern void add_entry_to_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee, + const char *object_type); + +extern bool check_bbf_schema_for_entry(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee); + +extern void del_from_bbf_schema(const char *schema_name, + const char *object_name, + const char *permission, + const char *grantee); + +extern bool check_bbf_schema_for_schema(const char *schema_name, + const char *object_name, + const char *permission); + +extern void clean_up_bbf_schema(const char *schema_name, + const char *object_name, + bool is_schema); + +extern void grant_perms_to_objects_in_schema(const char *schema_name, + const char *permission, + const char *grantee); + /***************************************** * DOMAIN MAPPING *****************************************/ @@ -258,11 +355,47 @@ 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); + +/***************************************** + * EXTENDED_PROPERTIES + *****************************************/ +#define BBF_EXTENDED_PROPERTIES_TABLE_NAME "babelfish_extended_properties" +#define BBF_EXTENDED_PROPERTIES_IDX_NAME "babelfish_extended_properties_pkey" + +#define Anum_bbf_extended_properties_dbid 1 +#define Anum_bbf_extended_properties_schema_name 2 +#define Anum_bbf_extended_properties_major_name 3 +#define Anum_bbf_extended_properties_minor_name 4 +#define Anum_bbf_extended_properties_type 5 +#define Anum_bbf_extended_properties_name 6 +#define Anum_bbf_extended_properties_orig_name 7 +#define Anum_bbf_extended_properties_value 8 +#define BBF_EXTENDED_PROPERTIES_NUM_COLS 8 + +extern Oid bbf_extended_properties_oid; +extern Oid bbf_extended_properties_idx_oid; + +extern Oid get_bbf_extended_properties_oid(void); +extern Oid get_bbf_extended_properties_idx_oid(void); + +typedef struct FormData_bbf_extended_properties +{ + int16 dbid; + NameData schema_name; + NameData major_name; + NameData minor_name; + VarChar type; + VarChar name; + VarChar orig_name; + bytea value; +} FormData_bbf_extended_properties; -extern Oid get_bbf_domain_mapping_oid(void); -extern Oid get_bbf_domain_mapping_idx_oid(void); +typedef FormData_bbf_extended_properties *Form_bbf_extended_properties; /***************************************** * Metadata Check Rule @@ -282,13 +415,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 +439,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 +457,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..c25fb924e2 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,211 @@ 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_KILL: + 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_CHANGE_DBOWNER: + case PLTSQL_STMT_GRANTSCHEMA: + case PLTSQL_STMT_FULLTEXTINDEX: + case PLTSQL_STMT_INSERT_BULK: + case PLTSQL_STMT_DBCC: + 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 +344,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 +410,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 +473,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..8a3f1e400b 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,39 +488,47 @@ 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); } + else if (IsA(expr, SubLink)) + { + return expression_tree_mutator(expr, pgtsql_expression_tree_mutator, NULL); + } 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)) { + qual = transform_likenode(qual); new_predicates = lappend(new_predicates, - transform_likenode(qual)); + expression_tree_mutator(qual, pgtsql_expression_tree_mutator, NULL)); } else new_predicates = lappend(new_predicates, qual); @@ -514,22 +547,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 +575,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 +593,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 +624,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 +645,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 +655,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 +664,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 +682,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 +691,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 +700,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 +709,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 +718,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 +727,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 +745,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 +754,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 701869076a..3254ce6805 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" @@ -39,9 +40,13 @@ #include "guc.h" #include "rolecmds.h" #include "pltsql.h" +#include "extendedproperty.h" +Oid sys_babelfish_db_seq_oid = InvalidOid; + +static Oid get_sys_babelfish_db_seq_oid(void); 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, @@ -51,14 +56,28 @@ 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 Oid +get_sys_babelfish_db_seq_oid() +{ + if(!OidIsValid(sys_babelfish_db_seq_oid)) + { + RangeVar *sequence = makeRangeVarFromNameList(stringToQualifiedNameList("sys.babelfish_db_seq")); + Oid seqid = RangeVarGetRelid(sequence, NoLock, false); + + Assert(OidIsValid(seqid)); + sys_babelfish_db_seq_oid = seqid; + } + return sys_babelfish_db_seq_oid; +} + static bool have_createdb_privilege(void) { - bool result = false; + bool result = false; HeapTuple utup; /* Superusers can always do everything */ @@ -69,6 +88,7 @@ have_createdb_privilege(void) if (HeapTupleIsValid(utup)) { result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb; + ReleaseSysCache(utup); } return result; @@ -77,19 +97,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); @@ -108,7 +128,6 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, /* create sysdatabases under current DB's DBO schema */ appendStringInfo(&query, "CREATE VIEW dummy.sysdatabases AS SELECT * FROM sys.sysdatabases; "); appendStringInfo(&query, "ALTER VIEW dummy.sysdatabases OWNER TO dummy; "); - appendStringInfo(&query, "GRANT SELECT ON dummy.sysdatabases TO dummy; "); /* create guest schema in the database. This has to be the last statement */ if (guest) @@ -117,9 +136,9 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, res = raw_parser(query.data, RAW_PARSE_DEFAULT); if (guest) - expected_stmt_num = list_length(logins) > 0 ? 10 : 9; + expected_stmt_num = list_length(logins) > 0 ? 9 : 8; else - expected_stmt_num = 7; + expected_stmt_num = 6; if (list_length(res) != expected_stmt_num) ereport(ERROR, @@ -130,12 +149,12 @@ 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); stmt = parsetree_nth_stmt(res, i++); - update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo); + update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo, NULL); if (guest) { @@ -145,6 +164,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; @@ -161,10 +181,7 @@ gen_createdb_subcmds(const char *schema, const char *dbo, const char *db_owner, stmt = parsetree_nth_stmt(res, i++); update_AlterTableStmt(stmt, schema, db_owner); - - stmt = parsetree_nth_stmt(res, i++); - update_GrantStmt(stmt, NULL, schema, db_owner); - + if (guest) { stmt = parsetree_nth_stmt(res, i++); @@ -184,20 +201,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 = 6; + 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) { @@ -208,6 +225,7 @@ gen_dropdb_subcmds(const char *schema, } /* Then drop db_owner and dbo in that order */ appendStringInfo(&query, "DROP OWNED BY dummy, dummy CASCADE; "); + appendStringInfo(&query, "REVOKE CREATE, CONNECT, TEMPORARY ON DATABASE dummy FROM dummy; "); appendStringInfo(&query, "DROP ROLE dummy; "); appendStringInfo(&query, "DROP ROLE dummy; "); @@ -225,9 +243,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) { @@ -242,6 +260,9 @@ gen_dropdb_subcmds(const char *schema, stmt = parsetree_nth_stmt(stmt_list, i++); update_DropOwnedStmt(stmt, list_make2(pstrdup(db_owner), pstrdup(dbo))); + stmt = parsetree_nth_stmt(stmt_list, i++); + update_GrantStmt(stmt, get_database_name(MyDatabaseId), NULL, dbo, NULL); + stmt = parsetree_nth_stmt(stmt_list, i++); update_DropRoleStmt(stmt, db_owner); stmt = parsetree_nth_stmt(stmt_list, i++); @@ -253,16 +274,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), @@ -279,8 +302,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 @@ -289,12 +312,18 @@ 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() { - int16 dbid; - int16 start = 0; +static int16 +getAvailDbid(void) +{ + int16 dbid; + int16 start = 0; - do { - dbid = DirectFunctionCall1(nextval, CStringGetTextDatum("sys.babelfish_db_seq")); + if(GetUserId() != get_role_oid("sysadmin", true)) + return InvalidDbid; + + do + { + dbid = nextval_internal(get_sys_babelfish_db_seq_oid(), false); if (start == 0) start = dbid; else if (start == dbid) @@ -304,17 +333,62 @@ 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 + dbid = DirectFunctionCall1(currval_oid, get_sys_babelfish_db_seq_oid()); + + bbf_set_current_user(prev_current_user); + + return dbid; +} + 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); @@ -333,23 +407,26 @@ 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; + int save_sec_context; + bool is_set_userid; + Oid save_userid; /* TODO: Extract options */ @@ -357,9 +434,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); @@ -368,10 +446,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))); } @@ -403,13 +482,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 */ @@ -452,25 +531,33 @@ 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(); { /* Run all subcommands */ foreach(parsetree_item, parsetree_list) { - Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; - PlannedStmt *wrapper; + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + PlannedStmt *wrapper; + is_set_userid = false; + if(stmt->type == T_CreateSchemaStmt || stmt->type == T_AlterTableStmt + || stmt->type == T_ViewStmt) + { + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(get_role_oid(dbo_role, true), + save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + is_set_userid = true; + } /* need to make a wrapper PlannedStmt */ wrapper = makeNode(PlannedStmt); wrapper->commandType = CMD_UTILITY; wrapper->canSetTag = false; wrapper->utilityStmt = stmt; 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; @@ -485,7 +572,9 @@ create_bbf_db_internal(const char *dbname, List *options, const char *owner, int None_Receiver, NULL); - /* make sure later steps can see the object created here */ + if(is_set_userid) + SetUserIdAndSecContext(save_userid, save_sec_context); + CommandCounterIncrement(); } set_cur_db(old_dbid, old_dbname); @@ -495,15 +584,21 @@ 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); + add_to_bbf_authid_user_ext(guest, "guest", dbname, "guest", NULL, false, true, false); else - add_to_bbf_authid_user_ext(guest, "guest", dbname, NULL, NULL, false, false, false); + add_to_bbf_authid_user_ext(guest, "guest", dbname, "guest", NULL, false, false, false); } } PG_CATCH(); { + if(is_set_userid) + SetUserIdAndSecContext(save_userid, save_sec_context); + /* Clean up. Restore previous state. */ bbf_set_current_user(prev_current_user); set_cur_db(old_dbid, old_dbname); @@ -518,22 +613,25 @@ 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; + int save_sec_context; + bool is_set_userid; + Oid save_userid; 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, @@ -544,7 +642,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)) { @@ -581,15 +679,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), @@ -597,7 +698,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); @@ -622,7 +723,15 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) { Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; PlannedStmt *wrapper; + is_set_userid = false; + if(stmt->type != T_DropRoleStmt && stmt->type != T_GrantStmt) + { + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(get_role_oid(dbo_role, true), + save_sec_context | SECURITY_LOCAL_USERID_CHANGE); + is_set_userid = true; + } /* need to make a wrapper PlannedStmt */ wrapper = makeNode(PlannedStmt); wrapper->commandType = CMD_UTILITY; @@ -640,7 +749,10 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) NULL, None_Receiver, NULL); - + + if(is_set_userid) + SetUserIdAndSecContext(save_userid, save_sec_context); + /* make sure later steps can see the object created here */ CommandCounterIncrement(); } @@ -652,12 +764,17 @@ drop_bbf_db(const char *dbname, bool missing_ok, bool force_drop) drop_related_bbf_namespace_entries(dbid); /* clean up corresponding db users */ drop_related_bbf_users(db_users_list); + /* delete extended property */ + delete_extended_property(dbid, NULL, NULL, NULL, NULL); /* Release the session-level exclusive lock */ UnlockLogicalDatabaseForSession(dbid, ExclusiveLock, true); } PG_CATCH(); { + if(is_set_userid) + SetUserIdAndSecContext(save_userid, save_sec_context); + /* Clean up. Restore previous state. */ bbf_set_current_user(prev_current_user); UnlockLogicalDatabaseForSession(dbid, ExclusiveLock, false); @@ -670,45 +787,48 @@ 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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + PG_RE_THROW(); } 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); @@ -718,19 +838,20 @@ 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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + PG_RE_THROW(); } PG_END_TRY(); PG_RETURN_INT32(0); @@ -738,24 +859,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); + GUC_CONTEXT_CONFIG, + 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); @@ -764,16 +886,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_sysdatabases_name, + sysdatabase_rel->rd_att, &is_null); + dbnames[i] = TextDatumGetCString(name); i++; @@ -781,7 +905,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); @@ -789,14 +913,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RE_THROW(); } @@ -808,11 +932,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); @@ -820,16 +944,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); @@ -849,21 +974,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)); @@ -880,23 +1005,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); @@ -912,40 +1037,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; } @@ -969,7 +1097,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); @@ -980,13 +1109,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(); @@ -1008,38 +1137,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); + GUC_CONTEXT_CONFIG, + 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)); @@ -1053,17 +1183,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + 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 c25fb302b3..ace5e862cb 100644 --- a/contrib/babelfishpg_tsql/src/dbcmds.h +++ b/contrib/babelfishpg_tsql/src/dbcmds.h @@ -2,9 +2,10 @@ #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); +extern int16 getDbidForLogicalDbRestore(Oid relid); #endif 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..631745e6dc 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,37 @@ 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; - } + case SQL_ERROR_6615: + case SQL_ERROR_155: + case SQL_ERROR_9810: + case SQL_ERROR_535: + case SQL_ERROR_15003: + { + 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 +171,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 +206,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 +252,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 +277,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 +302,15 @@ 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; - } + case SQL_ERROR_15003: + { + 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 +322,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 +337,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 +357,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 +402,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 +421,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 +445,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 +489,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 +553,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 +567,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 +579,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 +595,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 +608,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 +641,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 +654,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..1e4c6049b7 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 @@ -37,6 +38,7 @@ uint8_t override_txn_behaviour(PLtsql_stmt *stmt); #define SQL_ERROR_141 141 #define SQL_ERROR_142 142 #define SQL_ERROR_153 153 +#define SQL_ERROR_155 155 #define SQL_ERROR_180 180 #define SQL_ERROR_201 201 #define SQL_ERROR_206 206 @@ -57,6 +59,7 @@ uint8_t override_txn_behaviour(PLtsql_stmt *stmt); #define SQL_ERROR_512 512 #define SQL_ERROR_515 515 #define SQL_ERROR_517 517 +#define SQL_ERROR_535 535 #define SQL_ERROR_545 545 #define SQL_ERROR_547 547 #define SQL_ERROR_550 550 @@ -101,6 +104,7 @@ uint8_t override_txn_behaviour(PLtsql_stmt *stmt); #define SQL_ERROR_4901 4901 #define SQL_ERROR_4920 4920 #define SQL_ERROR_6401 6401 +#define SQL_ERROR_6615 6615 #define SQL_ERROR_8003 8003 #define SQL_ERROR_8004 8004 #define SQL_ERROR_8007 8007 @@ -133,6 +137,7 @@ uint8_t override_txn_behaviour(PLtsql_stmt *stmt); #define SQL_ERROR_9441 9441 #define SQL_ERROR_9451 9451 #define SQL_ERROR_9809 9809 +#define SQL_ERROR_9810 9810 #define SQL_ERROR_10610 10610 #define SQL_ERROR_10727 10727 #define SQL_ERROR_10733 10733 @@ -151,3 +156,4 @@ uint8_t override_txn_behaviour(PLtsql_stmt *stmt); #define SQL_ERROR_16948 16948 #define SQL_ERROR_16950 16950 #define SQL_ERROR_18456 18456 +#define SQL_ERROR_15003 15003 diff --git a/contrib/babelfishpg_tsql/src/extendedproperty.c b/contrib/babelfishpg_tsql/src/extendedproperty.c new file mode 100644 index 0000000000..751bcb8e87 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/extendedproperty.c @@ -0,0 +1,1167 @@ +/*------------------------------------------------------------------------- + * + * extendedproperty.c + * support extended property + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/genam.h" +#include "access/skey.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/indexing.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "tsearch/ts_locale.h" +#include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/datum.h" +#include "utils/formatting.h" +#include "utils/syscache.h" +#include "utils/fmgroids.h" +#include "utils/rel.h" + +#include "catalog.h" +#include "extendedproperty.h" +#include "multidb.h" +#include "pltsql.h" +#include "session.h" + +typedef enum ExtendedPropertyProc +{ + SP_ADDEXTENDEDPROPERTY = 0, + SP_UPDATEEXTENDEDPROPERTY, + SP_DROPEXTENDEDPROPERTY +} ExtendedPropertyProc; + +const char *const ExtendedPropertyTypeNames[] = { + "DATABASE", + "SCHEMA", + "TABLE", + "VIEW", + "SEQUENCE", + "PROCEDURE", + "FUNCTION", + "TYPE", + "TABLE COLUMN" +}; + +StaticAssertDecl(lengthof(ExtendedPropertyTypeNames) == EXTENDED_PROPERTY_MAX, + "array length mismatch"); + +PG_FUNCTION_INFO_V1(sp_addextendedproperty); +PG_FUNCTION_INFO_V1(sp_updateextendedproperty); +PG_FUNCTION_INFO_V1(sp_dropextendedproperty); +PG_FUNCTION_INFO_V1(fn_listextendedproperty); + +static void init_scan_key(ScanKeyData *scanKey, + int *nkeys, + int16 db_id, + const char *type, + const char *schema_name, + const char *major_name, + const char *minor_name, + const char *name); +static void sp_execextended_property(PG_FUNCTION_ARGS, ExtendedPropertyProc proc); +static bool get_extended_property_from_tuple(Relation relation, HeapTuple tuple, + Datum *values, bool *nulls, int len); +static char* get_value_by_name_from_array(ArrayType *array, const char *name); + +static void +init_scan_key(ScanKeyData *scanKey, + int *nkeys, + int16 db_id, + const char *type, + const char *schema_name, + const char *major_name, + const char *minor_name, + const char *name) +{ + *nkeys = 0; + ScanKeyInit(&scanKey[*nkeys], + Anum_bbf_extended_properties_dbid, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(db_id)); + (*nkeys)++; + + if (type) + { + ScanKeyInit(&scanKey[*nkeys], + Anum_bbf_extended_properties_type, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(type)); + (*nkeys)++; + } + + if (schema_name) + { + ScanKeyInit(&scanKey[*nkeys], + Anum_bbf_extended_properties_schema_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(schema_name)); + (*nkeys)++; + } + + if (major_name) + { + ScanKeyInit(&scanKey[*nkeys], + Anum_bbf_extended_properties_major_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(major_name)); + (*nkeys)++; + } + + if (minor_name) + { + ScanKeyInit(&scanKey[*nkeys], + Anum_bbf_extended_properties_minor_name, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum(minor_name)); + (*nkeys)++; + } + + if (name) + { + ScanKeyInit(&scanKey[*nkeys], + Anum_bbf_extended_properties_name, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(name)); + (*nkeys)++; + } +} + +void +delete_extended_property(int16 db_id, + const char *type, + const char *schema_name, + const char *major_name, + const char *minor_name) +{ + Relation rel; + int nkeys = 0; + ScanKeyData scanKey[5]; + SysScanDesc scan; + HeapTuple tuple; + + rel = table_open(get_bbf_extended_properties_oid(), RowExclusiveLock); + + init_scan_key(scanKey, &nkeys, db_id, type, schema_name, major_name, + minor_name, NULL); + + scan = systable_beginscan(rel, get_bbf_extended_properties_idx_oid(), true, + NULL, nkeys, scanKey); + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + CatalogTupleDelete(rel, &tuple->t_self); + } + + systable_endscan(scan); + table_close(rel, RowExclusiveLock); + + CommandCounterIncrement(); +} + +void +update_extended_property(int16 db_id, + const char *type, + const char *schema_name, + const char *major_name, + const char *minor_name, + int attnum, + const char *new_value) +{ + Relation rel; + int nkeys = 0; + ScanKeyData scanKey[5]; + SysScanDesc scan; + HeapTuple tuple, new_tuple; + Datum values[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + bool nulls[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + bool replaces[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + + rel = table_open(get_bbf_extended_properties_oid(), RowExclusiveLock); + + init_scan_key(scanKey, &nkeys, db_id, type, schema_name, major_name, + minor_name, NULL); + + scan = systable_beginscan(rel, get_bbf_extended_properties_idx_oid(), true, + NULL, nkeys, scanKey); + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + values[attnum - 1] = CStringGetDatum(new_value); + replaces[attnum - 1] = true; + + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + new_tuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + values, nulls, replaces); + + CatalogTupleUpdate(rel, &new_tuple->t_self, new_tuple); + + heap_freetuple(new_tuple); + } + + systable_endscan(scan); + table_close(rel, RowExclusiveLock); + + CommandCounterIncrement(); +} + +Datum +sp_addextendedproperty(PG_FUNCTION_ARGS) +{ + sp_execextended_property(fcinfo, SP_ADDEXTENDEDPROPERTY); + + PG_RETURN_VOID(); +} + +Datum +sp_updateextendedproperty(PG_FUNCTION_ARGS) +{ + sp_execextended_property(fcinfo, SP_UPDATEEXTENDEDPROPERTY); + + PG_RETURN_VOID(); +} + +Datum +sp_dropextendedproperty(PG_FUNCTION_ARGS) +{ + sp_execextended_property(fcinfo, SP_DROPEXTENDEDPROPERTY); + + PG_RETURN_VOID(); +} + +/* + * Main routine of sp_xxxextendedproperty. + * Now we support some types of extended property, such as database, schema, + * table, view, sequence, procedure, function, type, table column. We store type + * of extended property as well, like TABLE or TABLE COLUMN. Note that we store + * level1type with level2type. We will store PROCEDURE PARAMTER if we support + * extended property of procedure paramter. + * If we support more extended property, we should adapt sp_rename and + * bbf_ExecDropStmt as well. + */ +static void +sp_execextended_property(PG_FUNCTION_ARGS, ExtendedPropertyProc proc) +{ + char *name, *orig_name, + *level0type, *level0name, + *level1type, *level1name, + *level2type, *level2name; + bytea *value = NULL; + int16 db_id; + const char *type; + char *schema_name, *major_name, *minor_name, *var_object_name; + Oid schema_id, owner_id; + Oid db_owner, cur_user_id; + bool is_dbo = false; + Relation rel; + HeapTuple tuple; + int nkeys = 0; + ScanKeyData scanKey[6]; + SysScanDesc scan; + uint8 param_valid = 0; + char *procedure_name; + char *db_name = get_cur_db_name(); + + if (proc == SP_ADDEXTENDEDPROPERTY || proc == SP_UPDATEEXTENDEDPROPERTY) + { + orig_name = TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + value = PG_ARGISNULL(1) ? NULL : PG_GETARG_BYTEA_PP(1); + level0type = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); + level0name = PG_ARGISNULL(3) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(3)); + level1type = PG_ARGISNULL(4) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(4)); + level1name = PG_ARGISNULL(5) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(5)); + level2type = PG_ARGISNULL(6) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(6)); + level2name = PG_ARGISNULL(7) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(7)); + } + else if (proc == SP_DROPEXTENDEDPROPERTY) + { + orig_name = TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + level0type = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); + level0name = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); + level1type = PG_ARGISNULL(3) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(3)); + level1name = PG_ARGISNULL(4) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(4)); + level2type = PG_ARGISNULL(5) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(5)); + level2name = PG_ARGISNULL(6) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(6)); + } + + db_owner = get_role_oid(get_db_owner_name(db_name), false); + cur_user_id = GetUserId(); + if (is_member_of_role(cur_user_id, db_owner)) + { + is_dbo = true; + } + + db_id = get_cur_db_id(); + type = NULL; + schema_name = ""; + major_name = ""; + minor_name = ""; + name = NULL; + var_object_name = ""; + + if (orig_name) + { + remove_trailing_spaces(orig_name); + name = lowerstr(orig_name); + } + if (level0type) + { + remove_trailing_spaces(level0type); + level0type = lowerstr(level0type); + } + if (level0name) + { + remove_trailing_spaces(level0name); + level0name = lowerstr(level0name); + } + if (level1type) + { + remove_trailing_spaces(level1type); + level1type = lowerstr(level1type); + } + if (level1name) + { + remove_trailing_spaces(level1name); + level1name = lowerstr(level1name); + } + if (level2type) + { + remove_trailing_spaces(level2type); + level2type = lowerstr(level2type); + } + if (level2name) + { + remove_trailing_spaces(level2name); + level2name = lowerstr(level2name); + } + + switch (proc) + { + case 0: + procedure_name = "sp_addextendedproperty"; + break; + case 1: + procedure_name = "sp_updateextendedproperty"; + break; + case 2: + procedure_name = "sp_dropextendedproperty"; + break; + default: + Assert(false); + procedure_name = ""; + break; + } + + /* + * If param is not null, its length must not 0. + * orig_name must be not null and not empty. + */ + if ((!orig_name || strlen(orig_name) == 0) || + (level0type && strlen(level0type) == 0) || + (level0name && strlen(level0name) == 0) || + (level1type && strlen(level1type) == 0) || + (level1name && strlen(level1name) == 0) || + (level2type && strlen(level2type) == 0) || + (level2name && strlen(level2name) == 0)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("An invalid parameter or option was specified for procedure '%s'.", procedure_name))); + } + + /* + * Params are valid only when they are paired. + * We use bit map to store valid param and the valid bit maps are 000000, + * 110000, 111100, 111111. + */ + if (level0type) + param_valid |= (1 << 5); + if (level0name) + param_valid |= (1 << 4); + if (level1type) + param_valid |= (1 << 3); + if (level1name) + param_valid |= (1 << 2); + if (level2type) + param_valid |= (1 << 1); + if (level2name) + param_valid |= (1 << 0); + if (param_valid != 0 && param_valid != 48 && param_valid != 60 && param_valid != 63) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("An invalid parameter or option was specified for procedure '%s'.", procedure_name))); + } + + /* database */ + if (!level0type) + { + if (!is_dbo) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot find the object \"object specified\" because it does not exist or you do not have permissions."))); + } + + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_DATABASE]; + var_object_name = "object specified"; + } + else + { + /* schema or object in schema */ + if (strcmp(level0type, "schema") == 0) + { + Form_pg_namespace nspform; + + var_object_name = level0name; + + schema_name = get_physical_schema_name(db_name, level0name); + tuple = SearchSysCache1(NAMESPACENAME, CStringGetDatum(schema_name)); + + if (!HeapTupleIsValid(tuple)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Object is invalid. Extended properties are not permitted on '%s', or the object does not exist.", var_object_name))); + } + + nspform = (Form_pg_namespace) GETSTRUCT(tuple); + schema_id = nspform->oid; + owner_id = nspform->nspowner; + ReleaseSysCache(tuple); + + /* schema */ + if (!level1type) + { + if (!is_dbo && !is_member_of_role(cur_user_id, owner_id)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot find the object \"%s\" because it does not exist or you do not have permissions.", var_object_name))); + } + + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SCHEMA]; + } + /* object in schema */ + else + { + Oid reloid = InvalidOid; + + if (strcmp(level1type, "table") != 0 && + strcmp(level1type, "view") != 0 && + strcmp(level1type, "sequence") != 0 && + strcmp(level1type, "procedure") != 0 && + strcmp(level1type, "function") != 0 && + strcmp(level1type, "type") != 0) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Extended properties for object type %s are not currently supported in Babelfish.", level1type))); + } + + var_object_name = psprintf("%s.%s", level0name, level1name); + major_name = level1name; + truncate_tsql_identifier(major_name); + + if (strcmp(level1type, "table") == 0 || + strcmp(level1type, "view") == 0 || + strcmp(level1type, "sequence") == 0) + { + Form_pg_class classform; + char relkind; + + tuple = SearchSysCache2(RELNAMENSP, + CStringGetDatum(major_name), + ObjectIdGetDatum(schema_id)); + if (!HeapTupleIsValid(tuple)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Object is invalid. Extended properties are not permitted on '%s', or the object does not exist.", var_object_name))); + } + + classform = (Form_pg_class) GETSTRUCT(tuple); + reloid = classform->oid; + relkind = classform->relkind; + owner_id = classform->relowner; + ReleaseSysCache(tuple); + + if ((strcmp(level1type, "table") == 0 && (relkind != RELKIND_RELATION && relkind != RELPERSISTENCE_PERMANENT)) || + (strcmp(level1type, "view") == 0 && (relkind != RELKIND_VIEW && relkind != RELKIND_MATVIEW)) || + (strcmp(level1type, "sequence") == 0 && relkind != RELKIND_SEQUENCE)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Object is invalid. Extended properties are not permitted on '%s', or the object does not exist.", var_object_name))); + } + + if (!is_dbo && !is_member_of_role(cur_user_id, owner_id)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot find the object \"%s\" because it does not exist or you do not have permissions.", var_object_name))); + } + } + else if (strcmp(level1type, "procedure") == 0 || + strcmp(level1type, "function") == 0) + { + CatCList *catlist; + Form_pg_proc procform; + bool find = false; + + catlist = SearchSysCacheList1(PROCNAMEARGSNSP, + CStringGetDatum(major_name)); + for (int i = 0; i < catlist->n_members; i++) + { + tuple = &catlist->members[i]->tuple; + procform = (Form_pg_proc) GETSTRUCT(tuple); + if (procform->pronamespace == schema_id) + { + owner_id = procform->proowner; + find = true; + break; + } + } + ReleaseSysCacheList(catlist); + + if (!find) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Object is invalid. Extended properties are not permitted on '%s', or the object does not exist.", var_object_name))); + } + + if (!is_dbo && !is_member_of_role(cur_user_id, owner_id)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot find the object \"%s\" because it does not exist or you do not have permissions.", var_object_name))); + } + } + else if (strcmp(level1type, "type") == 0) + { + Form_pg_type typeform; + + tuple = SearchSysCache2(TYPENAMENSP, + CStringGetDatum(major_name), + ObjectIdGetDatum(schema_id)); + if (!HeapTupleIsValid(tuple)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Object is invalid. Extended properties are not permitted on '%s', or the object does not exist.", var_object_name))); + } + + typeform = (Form_pg_type) GETSTRUCT(tuple); + owner_id = typeform->typowner; + ReleaseSysCache(tuple); + + if (!is_dbo && !is_member_of_role(cur_user_id, owner_id)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot find the object \"%s\" because it does not exist or you do not have permissions.", var_object_name))); + } + } + + if (!level2type) + { + type = asc_toupper(level1type, strlen(level1type)); + } + else + { + char *temp; + + if (strcmp(level1type, "table") != 0 && + strcmp(level2type, "column") != 0) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Extended properties for object type %s are not currently supported in Babelfish.", level2type))); + } + + var_object_name = psprintf("%s.%s.%s", level0name, level1name, level2name); + minor_name = level2name; + truncate_tsql_identifier(minor_name); + + tuple = SearchSysCacheAttName(reloid, minor_name); + if (!HeapTupleIsValid(tuple)) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Object is invalid. Extended properties are not permitted on '%s', or the object does not exist.", var_object_name))); + } + ReleaseSysCache(tuple); + + temp = psprintf("%s %s", level1type, level2type); + type = asc_toupper(temp, strlen(temp)); + pfree(temp); + } + } + } + } + + /* insert/update/drop extended property */ + rel = table_open(get_bbf_extended_properties_oid(), RowExclusiveLock); + + init_scan_key(scanKey, &nkeys, db_id, type, schema_name, major_name, + minor_name, name); + + scan = systable_beginscan(rel, get_bbf_extended_properties_idx_oid(), true, + NULL, 6, scanKey); + if (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + if (proc == SP_ADDEXTENDEDPROPERTY) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Property cannot be added. Property '%s' already exists for '%s'.", name, var_object_name))); + } + } + else + { + if (proc == SP_UPDATEEXTENDEDPROPERTY || proc == SP_DROPEXTENDEDPROPERTY) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Property cannot be updated or deleted. Property '%s' does not exist for '%s'.", name, var_object_name))); + } + } + + if (proc == SP_ADDEXTENDEDPROPERTY) + { + Datum values[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + bool nulls[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + + values[0] = Int16GetDatum(db_id); + values[1] = CStringGetDatum(schema_name); + values[2] = CStringGetDatum(major_name); + values[3] = CStringGetDatum(minor_name); + values[4] = CStringGetTextDatum(type); + values[5] = CStringGetTextDatum(name); + values[6] = CStringGetTextDatum(orig_name); + if (value) + values[7] = CStringGetDatum(value); + else + nulls[7] = true; + + tuple = heap_form_tuple(RelationGetDescr(rel), values, nulls); + CatalogTupleInsert(rel, tuple); + heap_freetuple(tuple); + } + else if (proc == SP_UPDATEEXTENDEDPROPERTY) + { + Datum values[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + bool nulls[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + bool replaces[BBF_EXTENDED_PROPERTIES_NUM_COLS]; + HeapTuple new_tuple; + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replaces, false, sizeof(replaces)); + + if (value) + values[Anum_bbf_extended_properties_value - 1] = CStringGetDatum(value); + else + nulls[Anum_bbf_extended_properties_value - 1] = true; + replaces[Anum_bbf_extended_properties_value - 1] = true; + + new_tuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + values, nulls, replaces); + CatalogTupleUpdate(rel, &new_tuple->t_self, new_tuple); + heap_freetuple(new_tuple); + } + else if (proc == SP_DROPEXTENDEDPROPERTY) + { + CatalogTupleDelete(rel, &tuple->t_self); + } + + systable_endscan(scan); + table_close(rel, RowExclusiveLock); + + CommandCounterIncrement(); +} + +Datum +fn_listextendedproperty(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + char *name, + *level0type, *level0name, + *level1type, *level1name, + *level2type, *level2name; + int16 db_id; + const char *type; + char *schema_name, *major_name, *minor_name; + Relation rel; + HeapTuple tuple; + ScanKeyData scanKey[6]; + int nkeys; + SysScanDesc scan; + uint8 param_valid = 0; + Oid nspoid, sysname_oid, sql_variant_oid, colloid; + + name = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + level0type = PG_ARGISNULL(1) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(1)); + level0name = PG_ARGISNULL(2) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(2)); + level1type = PG_ARGISNULL(3) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(3)); + level1name = PG_ARGISNULL(4) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(4)); + level2type = PG_ARGISNULL(5) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(5)); + level2name = PG_ARGISNULL(6) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(6)); + + db_id = get_cur_db_id(); + type = NULL; + schema_name = ""; + major_name = ""; + minor_name = ""; + + if (name) + { + remove_trailing_spaces(name); + name = lowerstr(name); + } + if (level0type) + { + remove_trailing_spaces(level0type); + level0type = lowerstr(level0type); + } + if (level0name) + { + remove_trailing_spaces(level0name); + level0name = lowerstr(level0name); + } + if (level1type) + { + remove_trailing_spaces(level1type); + level1type = lowerstr(level1type); + } + if (level1name) + { + remove_trailing_spaces(level1name); + level1name = lowerstr(level1name); + } + if (level2type) + { + remove_trailing_spaces(level2type); + level2type = lowerstr(level2type); + } + if (level2name) + { + remove_trailing_spaces(level2name); + level2name = lowerstr(level2name); + } + + /* 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"))); + + nspoid = get_namespace_oid("sys", false); + sysname_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum("sysname"), + ObjectIdGetDatum(nspoid)); + sql_variant_oid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + CStringGetDatum("sql_variant"), + ObjectIdGetDatum(nspoid)); + colloid = tsql_get_server_collation_oid_internal(false); + + /* 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, "objtype", sysname_oid, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objname", sysname_oid, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name", sysname_oid, 128, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "value", sql_variant_oid, -1, 0); + tupdesc = BlessTupleDesc(tupdesc); + + /* And set the correct collations to the required fields. */ + TupleDescInitEntryCollation(tupdesc, (AttrNumber) 1, colloid); + TupleDescInitEntryCollation(tupdesc, (AttrNumber) 2, colloid); + TupleDescInitEntryCollation(tupdesc, (AttrNumber) 3, colloid); + TupleDescInitEntryCollation(tupdesc, (AttrNumber) 4, colloid); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + /* generate junk in short-term context */ + MemoryContextSwitchTo(oldcontext); + + /* If param is not null, its length must not 0. */ + if ((name && strlen(name) == 0) || + (level0type && strlen(level0type) == 0) || + (level0name && strlen(level0name) == 0) || + (level1type && strlen(level1type) == 0) || + (level1name && strlen(level1name) == 0) || + (level2type && strlen(level2type) == 0) || + (level2name && strlen(level2name) == 0)) + goto end; + /* + * Params are valid only when they are continuous. + * We use bit map to store valid param and the valid bit maps are 100000, + * 110000, 111000, 111100, 111110, 111111. + */ + if (level0type && strlen(level0type) != 0) + param_valid |= (1 << 5); + if (level0name && strlen(level0name) != 0) + param_valid |= (1 << 4); + if (level1type && strlen(level1type) != 0) + param_valid |= (1 << 3); + if (level1name && strlen(level1name) != 0) + param_valid |= (1 << 2); + if (level2type && strlen(level2type) != 0) + param_valid |= (1 << 1); + if (level2name && strlen(level2name) != 0) + param_valid |= (1 << 0); + param_valid ^= 63; + if (((param_valid + 1) & param_valid) != 0) + goto end; + + /* database */ + if (!level0type) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_DATABASE]; + } + else + { + /* schema or object in schema */ + if (strcmp(level0type, "schema") == 0) + { + schema_name = get_physical_schema_name(get_cur_db_name(), level0name); + + /* schema */ + if (!level1type) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SCHEMA]; + } + /* object in schema */ + else + { + major_name = level1name; + truncate_tsql_identifier(major_name); + + if (!level2type) + type = asc_toupper(level1type, strlen(level1type)); + else + { + char *temp; + + temp = psprintf("%s %s", level1type, level2type); + type = asc_toupper(temp, strlen(temp)); + pfree(temp); + + minor_name = level2name; + truncate_tsql_identifier(minor_name); + } + } + } + } + rel = table_open(get_bbf_extended_properties_oid(), AccessShareLock); + + init_scan_key(scanKey, &nkeys, db_id, type, schema_name, major_name, + minor_name, name); + + scan = systable_beginscan(rel, get_bbf_extended_properties_idx_oid(), true, + NULL, nkeys, scanKey); + while (HeapTupleIsValid(tuple = systable_getnext(scan))) + { + Datum values[4]; + bool nulls[4]; + + if (get_extended_property_from_tuple(rel, tuple, values, nulls, 4)) + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + systable_endscan(scan); + table_close(rel, RowExclusiveLock); + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + +end: + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + PG_RETURN_NULL(); +} + +extern const char *ATTOPTION_BBF_ORIGINAL_TABLE_NAME; +extern const char *ATTOPTION_BBF_ORIGINAL_NAME; + +static char* +get_value_by_name_from_array(ArrayType *array, const char *name) +{ + int i; + + for (i = 1; i <= ARR_DIMS(array)[0]; i++) + { + Datum d; + bool isnull; + char *s; + char *p; + + d = array_ref(array, 1, &i, + -1 /* varlenarray */ , + -1 /* TEXT's typlen */ , + false /* TEXT's typbyval */ , + TYPALIGN_INT /* TEXT's typalign */ , + &isnull); + if (isnull) + continue; + + s = TextDatumGetCString(d); + p = strchr(s, '='); + if (p) + *p++ = '\0'; + + if (strcmp(s, name) == 0) + return p; + } + return NULL; +} + +/* + * Extract columns from extended property tuple and filter rows that + * current user does not has read-only privilege. + * + * Privileges are usage privilege on schema/type, select privilege on + * table/view/sequence/table column, execute privilege on procedure/function. + * + * We only check privilege of low level type. If type is TABLE COLUMN, we only + * check privilege of table column, skip privilege of schema or table. + */ +static bool +get_extended_property_from_tuple(Relation relation, HeapTuple tuple, + Datum *values, bool *nulls, int len) +{ + Form_bbf_extended_properties bep; + char *schema_name, *major_name, *minor_name, *type; + char *original_major_name = NULL, *original_minor_name = NULL; + Oid cur_user_id; + Oid schema_id, reloid = InvalidOid, procoid, typeoid; + HeapTuple heaptuple; + int16 attnum; + Datum datum; + bool isnull; + + type = ""; + schema_name = ""; + major_name = ""; + minor_name = ""; + + /* check if have read-only permission */ + cur_user_id = GetUserId(); + + bep = (Form_bbf_extended_properties) GETSTRUCT(tuple); + + /* + * we must use heap_getattr instead of GETSTRUCT, because type of Varchar + * doesn't have fix length. + */ + datum = heap_getattr(tuple, Anum_bbf_extended_properties_type, + RelationGetDescr(relation), &isnull); + type = TextDatumGetCString(datum); + schema_name = NameStr(bep->schema_name); + + if (strcmp(schema_name, "") != 0) + { + heaptuple = SearchSysCache1(NAMESPACENAME, + CStringGetDatum(schema_name)); + + if (!HeapTupleIsValid(heaptuple)) + return false; + + schema_id = ((Form_pg_namespace) GETSTRUCT(heaptuple))->oid; + ReleaseSysCache(heaptuple); + + if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SCHEMA]) == 0 && + pg_namespace_aclcheck(schema_id, cur_user_id, ACL_USAGE | ACL_CREATE) != ACLCHECK_OK) + return false; + + major_name = NameStr(bep->major_name); + if (strcmp(major_name, "") != 0) + { + /* + * We use strncmp rather than strcmp because we need to get relation + * oid before we get to lower layer. For example, the type is + * "TABLE COLUMN", we need to get table oid here. + */ + if (strncmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE], 5) == 0 || + strncmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_VIEW], 4) == 0 || + strncmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SEQUENCE], 8) == 0) + { + Form_pg_class classform; + ArrayType *reloptions; + + heaptuple = SearchSysCache2(RELNAMENSP, + CStringGetDatum(major_name), + ObjectIdGetDatum(schema_id)); + if (!HeapTupleIsValid(heaptuple)) + return false; + + classform = (Form_pg_class) GETSTRUCT(heaptuple); + reloid = classform->oid; + datum = SysCacheGetAttr(RELOID, heaptuple, + Anum_pg_class_reloptions, &isnull); + if (!isnull) + { + reloptions = DatumGetArrayTypeP(datum); + original_major_name = get_value_by_name_from_array(reloptions, ATTOPTION_BBF_ORIGINAL_TABLE_NAME); + } + ReleaseSysCache(heaptuple); + + if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_VIEW]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SEQUENCE]) == 0) + { + if (pg_class_aclcheck(reloid, cur_user_id, ACL_SELECT | ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_REFERENCES | ACL_TRIGGER) != ACLCHECK_OK) + return false; + } + } + else if (strncmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_PROCEDURE], 9) == 0 || + strncmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_FUNCTION], 8) == 0) + { + CatCList *catlist; + Form_pg_proc procform; + bool find = false; + + catlist = SearchSysCacheList1(PROCNAMEARGSNSP, + CStringGetDatum(major_name)); + for (int i = 0; i < catlist->n_members; i++) + { + heaptuple = &catlist->members[i]->tuple; + procform = (Form_pg_proc) GETSTRUCT(heaptuple); + if (procform->pronamespace == schema_id) + { + procoid = procform->oid; + find = true; + break; + } + } + ReleaseSysCacheList(catlist); + + if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_PROCEDURE]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_FUNCTION]) == 0) + { + if (!find || + pg_proc_aclcheck(procoid, cur_user_id, ACL_EXECUTE) != ACLCHECK_OK) + return false; + } + } + else if (strncmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TYPE], 4) == 0) + { + Form_pg_type typeform; + + heaptuple = SearchSysCache2(TYPENAMENSP, + CStringGetDatum(major_name), + ObjectIdGetDatum(schema_id)); + if (!HeapTupleIsValid(heaptuple)) + return false; + + typeform = (Form_pg_type) GETSTRUCT(heaptuple); + typeoid = typeform->oid; + ReleaseSysCache(heaptuple); + + if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TYPE]) == 0) + { + if (pg_type_aclcheck(typeoid, cur_user_id, ACL_USAGE) != ACLCHECK_OK) + return false; + } + } + + minor_name = NameStr(bep->minor_name); + if (strcmp(minor_name, "") != 0) + { + if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE_COLUMN]) == 0) + { + Form_pg_attribute attform; + ArrayType *attoptions; + + heaptuple = SearchSysCacheAttName(reloid, minor_name); + if (!HeapTupleIsValid(heaptuple)) + return false; + + attform = (Form_pg_attribute) GETSTRUCT(heaptuple); + attnum = attform->attnum; + datum = SysCacheGetAttr(ATTNAME, heaptuple, + Anum_pg_attribute_attoptions, + &isnull); + if (!isnull) + { + attoptions = DatumGetArrayTypeP(datum); + original_minor_name = get_value_by_name_from_array(attoptions, ATTOPTION_BBF_ORIGINAL_NAME); + } + ReleaseSysCache(heaptuple); + + if (pg_class_aclcheck(reloid, cur_user_id, ACL_SELECT | ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_REFERENCES | ACL_TRIGGER) != ACLCHECK_OK && + pg_attribute_aclcheck(reloid, attnum, cur_user_id, ACL_SELECT | ACL_INSERT | ACL_UPDATE | ACL_REFERENCES) != ACLCHECK_OK) + return false; + } + } + } + } + + MemSet(values, 0, len); + MemSet(nulls, 0, len); + + if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_DATABASE]) == 0) + { + nulls[0] = true; + nulls[1] = true; + } + else if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SCHEMA]) == 0) + { + values[0] = CStringGetTextDatum(ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SCHEMA]); + values[1] = CStringGetTextDatum(get_logical_schema_name(schema_name, true)); + } + else if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_VIEW]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SEQUENCE]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_PROCEDURE]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_FUNCTION]) == 0 || + strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TYPE]) == 0) + { + values[0] = CStringGetTextDatum(type); + values[1] = CStringGetTextDatum(original_major_name ? original_major_name : major_name); + } + else if (strcmp(type, ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE_COLUMN]) == 0) + { + values[0] = CStringGetTextDatum("COLUMN"); + values[1] = CStringGetTextDatum(original_minor_name ? original_minor_name : minor_name); + } + + datum = heap_getattr(tuple, Anum_bbf_extended_properties_orig_name, + RelationGetDescr(relation), &isnull); + values[2] = datumCopy(datum, false, -1); + datum = heap_getattr(tuple, Anum_bbf_extended_properties_value, + RelationGetDescr(relation), &isnull); + values[3] = datumCopy(datum, false, -1); + + return true; +} diff --git a/contrib/babelfishpg_tsql/src/extendedproperty.h b/contrib/babelfishpg_tsql/src/extendedproperty.h new file mode 100644 index 0000000000..99ccd7a4c4 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/extendedproperty.h @@ -0,0 +1,33 @@ +#ifndef EXTENDEDPROPERTY_H +#define EXTENDEDPROPERTY_H + +typedef enum ExtendedPropertyType +{ + EXTENDED_PROPERTY_DATABASE = 0, + EXTENDED_PROPERTY_SCHEMA, + EXTENDED_PROPERTY_TABLE, + EXTENDED_PROPERTY_VIEW, + EXTENDED_PROPERTY_SEQUENCE, + EXTENDED_PROPERTY_PROCEDURE, + EXTENDED_PROPERTY_FUNCTION, + EXTENDED_PROPERTY_TYPE, + EXTENDED_PROPERTY_TABLE_COLUMN, + EXTENDED_PROPERTY_MAX /* should be last */ +} ExtendedPropertyType; + +extern const char *const ExtendedPropertyTypeNames[]; + +extern void delete_extended_property(int16 db_id, + const char *type, + const char *schema_name, + const char *major_name, + const char *minor_name); +extern void update_extended_property(int16 db_id, + const char *type, + const char *schema_name, + const char *major_name, + const char *minor_name, + int attnum, + const char *new_value); + +#endif \ No newline at end of file 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/fts.c b/contrib/babelfishpg_tsql/src/fts.c new file mode 100644 index 0000000000..389c40c9e5 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/fts.c @@ -0,0 +1,56 @@ +#include "postgres.h" +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/memutils.h" +#include "fts_data.h" +#include "guc.h" + +PG_FUNCTION_INFO_V1(babelfish_fts_rewrite); + +Datum +babelfish_fts_rewrite(PG_FUNCTION_ARGS) +{ + text* input_text = PG_GETARG_TEXT_P(0); + char* input_str = text_to_cstring(input_text); + char* translated_query; + text* result_text = NULL; // Initialize result_text to NULL + + if (!pltsql_allow_fulltext_parser) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Full Text Search is not yet supported."))); + } + + PG_TRY(); + { + // Switch to a suitable memory context if necessary + if (!CurrentMemoryContext) { + MemoryContextSwitchTo(TopMemoryContext); + } + fts_scanner_init(input_str); + + if (fts_yyparse(&translated_query) != 0) + fts_yyerror(&translated_query, "fts parser failed"); + + fts_scanner_finish(); + } + PG_CATCH(); + { + PG_RE_THROW(); + } + PG_END_TRY(); + + if (translated_query) { + result_text = cstring_to_text(translated_query); + } + + // Make sure to free allocated memory + pfree(input_str); + + if (result_text) { + PG_RETURN_TEXT_P(result_text); + } else { + PG_RETURN_NULL(); + } +} diff --git a/contrib/babelfishpg_tsql/src/fts_data.h b/contrib/babelfishpg_tsql/src/fts_data.h new file mode 100644 index 0000000000..6068597725 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/fts_data.h @@ -0,0 +1,13 @@ +#ifndef FTS_PARSER_H +#define FTS_PARSER_H + +/* in fts_scan.l */ +extern int fts_yylex(void); +extern void fts_yyerror(char **result, const char *message) pg_attribute_noreturn(); +extern void fts_scanner_init(const char *str); +extern void fts_scanner_finish(void); + +/* in fts_parser.y */ +extern int fts_yyparse(char **result); + +#endif /* FTS_PARSER_H */ diff --git a/contrib/babelfishpg_tsql/src/fts_parser.y b/contrib/babelfishpg_tsql/src/fts_parser.y new file mode 100644 index 0000000000..a94d386718 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/fts_parser.y @@ -0,0 +1,265 @@ +%{ +#include "postgres.h" +#include +#include "fts_data.h" + +/* All grammar constructs return strings */ +#define FTS_YYSTYPE char * + +/* + * Bison doesn't allocate anything that needs to live across parser calls, + * so we can easily have it use palloc instead of palloc. This prevents + * memory leaks if we error out during parsing. Note this only works with + * bison >= 2.0. However, in bison 1.875 the default is to use alloca() + * if possible, so there's not really much problem anyhow, at least if + * you're building with gcc. + */ +#define YYpALLOC palloc +#define YYFREE pfree + +static char *scanbuf; +static int scanbuflen; + +static char* translate_simple_term(const char* s); +static char *trim(char *s); +static char *trimInsideQuotes(char *s); + +%} + +%token WORD_TOKEN WS_TOKEN TEXT_TOKEN PREFIX_TERM_TOKEN GENERATION_TERM_TOKEN AND_TOKEN AND_NOT_TOKEN OR_TOKEN INFLECTIONAL_TOKEN THESAURUS_TOKEN FORMSOF_TOKEN O_PAREN_TOKEN C_PAREN_TOKEN COMMA_TOKEN +%left OR_TOKEN +%left AND_TOKEN +%left AND_NOT_TOKEN + +%start contains_search_condition +%define api.prefix {fts_yy} +%parse-param {char** result} +%expect 0 + +/* Grammar follows */ +%% + +contains_search_condition: + simple_term + | prefix_term + | generation_term + ; + +simple_term: + WORD_TOKEN { + *result = translate_simple_term($1); + } + | TEXT_TOKEN { + *result = translate_simple_term($1); + } + | WS_TOKEN WORD_TOKEN { + *result = translate_simple_term($2); + } + | WORD_TOKEN WS_TOKEN { + *result = translate_simple_term($1); + } + | WS_TOKEN WORD_TOKEN WS_TOKEN { + *result = translate_simple_term($2); + } + | WS_TOKEN TEXT_TOKEN { + *result = translate_simple_term($2); + } + | TEXT_TOKEN WS_TOKEN { + *result = translate_simple_term($1); + } + | WS_TOKEN TEXT_TOKEN WS_TOKEN { + *result = translate_simple_term($2); + } + ; + +prefix_term: + PREFIX_TERM_TOKEN { + fts_yyerror(NULL, "Prefix term is not currently supported in Babelfish"); + } + ; + +generation_term: + FORMSOF_TOKEN O_PAREN_TOKEN generation_type COMMA_TOKEN simple_term_list C_PAREN_TOKEN { + fts_yyerror(NULL, "Generation term is not currently supported in Babelfish"); + } + ; + +generation_type: + INFLECTIONAL_TOKEN { + $$ = $1; + } + | THESAURUS_TOKEN { + $$ = $1; + } + ; + +simple_term_list: + simple_term { + $$ = $1; + } + | simple_term_list COMMA_TOKEN simple_term { + $$ = $1; + } + ; + +%% + +/* Helper function that takes in a word or phrase and returns the same word/phrase in Postgres format + * Example: 'word' is rewritten into 'word'; '"word1 word2 word3"' is rewritten into 'word1<->word2<->word3' + * Case 1: 'word' = 'word' + * Case 2: '"word1 word2 word3"' = 'word1<->word2<->word3' + * Case 3: ' word' = 'word' || 'word ' = 'word' || ' word ' = 'word' + * Case 4: '" word1 word2"' = 'word1<->word2' || '"word1 word2 "' = 'word1<->word2' || '" word1 word2 "' = 'word1<->word2' + * Trivial Case: spaces before and after double quotes, Example - ' "word1 word2" ' = 'word1<->word2' + */ +static +char* translate_simple_term(const char* inputStr) { + + int inputLength; + int outputSize; + char* output; + const char* inputPtr; + char* outputPtr; + char* trimmedInputStr; + + // Check for empty input + if (inputStr == NULL) { + return NULL; + } + + trimmedInputStr = (char*)palloc(strlen(inputStr) + 1); + strcpy(trimmedInputStr, inputStr); + + // removing trailing and leading spaces + trim(trimmedInputStr); + inputLength = strlen(trimmedInputStr); + + // Check if the input is a phrase enclosed in double quotes + if (trimmedInputStr[0] == '"' && trimmedInputStr[inputLength - 1] == '"') { + trimInsideQuotes(trimmedInputStr); + inputLength = strlen(trimmedInputStr); + outputSize = inputLength - 2; // Exclude both quotes + output = (char*)palloc(outputSize + 1); // +1 for the null terminator + if (output == NULL) { + return NULL; + } + + // Initialize pointers for input and output + inputPtr = trimmedInputStr; + outputPtr = output; + + while (*inputPtr != '\0') { + if (*inputPtr == ' ') { + // Replace space with "<->" + *outputPtr++ = '<'; + *outputPtr++ = '-'; + *outputPtr++ = '>'; + } else { + // Copy the character + *outputPtr++ = *inputPtr; + } + inputPtr++; + } + *outputPtr = '\0'; + + return output; + } else { + // It's a single word, so no transformation needed + return strdup(trimmedInputStr); + } +} + +// Function to remove leading and trailing spaces of a string +static char *trim(char *s) { + size_t length; + size_t start; + size_t end; + size_t newLength; + + if (s == NULL) { + return NULL; + } + + length = strlen(s); + if (length == 0) { + return s; // Empty string, nothing to trim + } + + start = 0; + end = length - 1; + + // Trim leading spaces + while (start < length && isspace(s[start])) { + start++; + } + + // Trim trailing spaces + while (end > start && isspace(s[end])) { + end--; + } + + // Calculate the new length + newLength = end - start + 1; + + // Shift the non-space part to the beginning of the string + memmove(s, s + start, newLength); + + // Null-terminate the result + s[newLength] = '\0'; + + return s; +} + +// Function to remove leading and trailing spaces inside double quotes +static char *trimInsideQuotes(char *s) { + size_t length; + size_t start; + size_t end; + size_t i; + size_t newLength; + bool insideQuotes; + + if (s == NULL) { + return NULL; + } + + length = strlen(s); + if (length == 0) { + return s; // Empty string, nothing to trim + } + + insideQuotes = false; + start = 1; + end = length - 2; + + for (i = 0; i < length; i++) { + if (s[i] == '"') { + insideQuotes = !insideQuotes; + } + + if (!insideQuotes) { + // Trim leading spaces inside quotes + while (start < length && isspace(s[start])) { + start++; + } + + // Trim trailing spaces inside quotes + while (end > start && isspace(s[end])) { + end--; + } + } + } + + // Calculate the new length + newLength = end - start + 1; + + // Shift the non-space part to the beginning of the string + memmove(s, s + start, newLength); + + // Null-terminate the result + s[newLength] = '\0'; + + return s; +} + +# include "fts_scan.c" \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/fts_scan.l b/contrib/babelfishpg_tsql/src/fts_scan.l new file mode 100644 index 0000000000..0ee1a82376 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/fts_scan.l @@ -0,0 +1,88 @@ +%{ +#include "fts_data.h" + +/* LCOV_EXCL_START */ + +/* No reason to constrain amount of data slurped */ +#define YY_READ_BUF_SIZE 16777216 + +/* Handles to the buffer that the lexer uses internally */ +static YY_BUFFER_STATE scanbufhandle; +%} + +%option never-interactive +%option nodefault +%option noinput +%option nounput +%option noyywrap +%option yylineno +%option warn +%option prefix="fts_yy" + +%% + +"AND" { yylval = "AND"; yyerror(NULL, "Boolean operator is not currently supported in Babelfish"); return AND_TOKEN; } +"AND NOT" { yylval = "AND NOT"; yyerror(NULL, "Boolean operator is not currently supported in Babelfish"); return AND_NOT_TOKEN; } +"OR" { yylval = "OR"; yyerror(NULL, "Boolean operator is not currently supported in Babelfish"); return OR_TOKEN; } +"INFLECTIONAL" { yylval = "INFLECTIONAL"; return INFLECTIONAL_TOKEN; } +"THESAURUS" { yylval = "THESAURUS"; return THESAURUS_TOKEN; } +"FORMSOF" { yylval = "FORMSOF"; return FORMSOF_TOKEN; } +"(" { yylval = "("; return O_PAREN_TOKEN; } +")" { yylval = ")"; return C_PAREN_TOKEN; } +"," { yylval = ","; return COMMA_TOKEN; } +[ \t\r\n]+ { yylval = " "; return WS_TOKEN; } + +\"[^"]+\*\" { if (yytext[strlen(yytext)-2] == ' ') { yyerror(NULL, "Syntax error, space is not allowed before *"); } yylval = yytext; return PREFIX_TERM_TOKEN; } // Handle prefix terms +[a-zA-Z0-9]+ { yylval = yytext; return WORD_TOKEN; } // Handle individual words +\"[^"*]+\" { yylval = yytext; return TEXT_TOKEN; } // Handle double-quoted phrases + +FORMSOF\s*\(\s*(INFLECTIONAL|THESAURUS)\s*,\s*((\w+)|(\"[\w\s]+\"))(\s*,\s*((\w+)|(\"[\w\s]+\")))*\s*\) { yylval = yytext; return GENERATION_TERM_TOKEN; } // Handle FORMSOF generation term + +. { return yytext[0]; } // Other characters are returned as-is + +%% + +/* LCOV_EXCL_STOP */ + +void yyerror(char **result, const char *message) { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s", message))); +} + +/* + * Called before any actual parsing is done + */ +void +fts_scanner_init(const char *str) +{ + Size slen = strlen(str); + + /* + * Might be left over after ereport() + */ + if (YY_CURRENT_BUFFER) + yy_delete_buffer(YY_CURRENT_BUFFER); + + /* + * Make a scan buffer with special termination needed by flex. + */ + scanbuflen = slen; + scanbuf = palloc(slen + 2); + memcpy(scanbuf, str, slen); + scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; + scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); + + BEGIN(INITIAL); +} + + +/* + * Called after parsing is done to clean up after fts_scanner_init() + */ +void +fts_scanner_finish(void) +{ + yy_delete_buffer(scanbufhandle); + pfree(scanbuf); +} diff --git a/contrib/babelfishpg_tsql/src/guc.c b/contrib/babelfishpg_tsql/src/guc.c index a64203e482..8e6e99dade 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" @@ -10,61 +10,64 @@ #include "pltsql.h" #include "pl_explain.h" #include "miscadmin.h" +#include "access/parallel.h" #define PLTSQL_SESSION_ISOLATION_LEVEL "default_transaction_isolation" #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; +char *pltsql_psql_logical_babelfish_db_name = NULL; +int pltsql_lock_timeout = -1; +bool pltsql_enable_linked_servers = true; +bool pltsql_allow_windows_login = true; +bool pltsql_allow_fulltext_parser = false; + +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,43 +80,43 @@ 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_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); -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 bool check_enable_pg_hint(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}, @@ -127,261 +130,303 @@ 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 const struct config_enum_entry bbf_isolation_options[] = { + {"off", ISOLATION_OFF, false}, + {"pg_isolation", PG_ISOLATION, false}, + {NULL, ISOLATION_OFF, false}, +}; + +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; -} - -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; + return true; } -static bool check_rowcount (int *newval, void **extra, GucSource source) +static bool +check_cursor_close_on_commit(bool *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"))); - } + 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 = 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 */ + *newval = false; /* overwrite to a default value */ } - return true; + 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 bool +check_enable_pg_hint(bool *newval, void **extra, GucSource source) +{ + /* + * Parallel workers send data to the leader, not the client. They always + * send data using pg_hint_plan.enable_hint_plan. + */ + if (IsParallelWorker() && !InitializingParallelWorker) + { + /* + * A change other than during startup, for example due to a SET clause + * attached to a function definition, should be rejected, as there is + * nothing we can do inside the worker to make it take effect. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_TRANSACTION_STATE), + errmsg("cannot change enable_hint_plan during a parallel operation"))); + } return true; } -static void assign_enable_pg_hint (bool newval, void *extra) + +static void +assign_enable_pg_hint(bool newval, void *extra) { + if (IsParallelWorker()) + return; + if (newval) { /* Will throw an error if pg_hint_plan is not installed */ @@ -392,12 +437,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); } /* @@ -412,107 +458,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); + 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; + 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 (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) @@ -523,14 +582,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) @@ -540,17 +601,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) @@ -558,237 +620,256 @@ 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); + + /* GUC for enabling or disabling full text search features */ + DefineCustomBoolVariable("babelfishpg_tsql.allow_fulltext_parser", + gettext_noop("GUC for enabling or disabling full text search features"), + NULL, + &pltsql_allow_fulltext_parser, + false, + PGC_SUSET, + GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_SUPERUSER_ONLY, + 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); + + DefineCustomStringVariable("psql_logical_babelfish_db_name", + gettext_noop("Sets a Babelfish database name from PG endpoint"), + NULL, + &pltsql_psql_logical_babelfish_db_name, + NULL, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + 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, - check_rowcount, 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"), @@ -855,130 +936,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", @@ -990,500 +1071,536 @@ 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, + check_enable_pg_hint, 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; +int escape_hatch_set_transaction_isolation_level = EH_STRICT; +int pltsql_isolation_level_repeatable_read = ISOLATION_OFF; +int pltsql_isolation_level_serializable = ISOLATION_OFF; 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 search"), + 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); + + /* SET TRANSACTION ISOLATION */ + DefineCustomEnumVariable("babelfishpg_tsql.escape_hatch_set_transaction_isolation_level", + gettext_noop("escape hatch for SET TRANSACTION ISOLATION LEVEL"), + NULL, + &escape_hatch_set_transaction_isolation_level, + EH_STRICT, + escape_hatch_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); + + /* REPEATABLE READ MAPPING */ + DefineCustomEnumVariable("babelfishpg_tsql.isolation_level_repeatable_read", + gettext_noop("Select mapping for isolation level reapeatable read"), + NULL, + &pltsql_isolation_level_repeatable_read, + ISOLATION_OFF, + bbf_isolation_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); + + /* SERIALIZABLE MAPPING */ + DefineCustomEnumVariable("babelfishpg_tsql.isolation_level_serializable", + gettext_noop("Select mapping for isolation level serializable"), + NULL, + &pltsql_isolation_level_serializable, + ISOLATION_OFF, + bbf_isolation_options, + PGC_USERSET, + GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE | GUC_DISALLOW_IN_AUTO_FILE, + NULL, NULL, NULL); } void @@ -1514,4 +1631,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..e3733e41b8 100644 --- a/contrib/babelfishpg_tsql/src/guc.h +++ b/contrib/babelfishpg_tsql/src/guc.h @@ -1,13 +1,28 @@ #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; + +typedef enum IsolationOptions +{ + ISOLATION_OFF, PG_ISOLATION +} IsolationOptions; extern bool pltsql_fmtonly; extern bool pltsql_enable_create_alter_view_from_pg; extern bool pltsql_enable_linked_servers; extern bool pltsql_allow_windows_login; +extern bool pltsql_allow_fulltext_parser; +extern char *pltsql_psql_logical_babelfish_db_name; +extern int pltsql_isolation_level_repeatable_read; +extern int pltsql_isolation_level_serializable; extern void define_custom_variables(void); extern void pltsql_validate_set_config_function(char *name, char *value); @@ -17,13 +32,15 @@ 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); +extern void pltsql_remove_current_query_env(void); #endif diff --git a/contrib/babelfishpg_tsql/src/hooks.c b/contrib/babelfishpg_tsql/src/hooks.c index 5571b4240d..b0f955b5d5 100644 --- a/contrib/babelfishpg_tsql/src/hooks.c +++ b/contrib/babelfishpg_tsql/src/hooks.c @@ -4,6 +4,7 @@ #include "access/htup.h" #include "access/table.h" #include "catalog/heap.h" +#include "utils/pg_locale.h" #include "access/xact.h" #include "access/relation.h" #include "catalog/namespace.h" @@ -16,12 +17,14 @@ #include "catalog/pg_trigger.h" #include "catalog/pg_trigger_d.h" #include "catalog/pg_type.h" +#include "catalog/pg_operator.h" #include "commands/copy.h" #include "commands/explain.h" #include "commands/tablecmds.h" #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" @@ -36,6 +39,7 @@ #include "parser/parse_utilcmd.h" #include "parser/parse_target.h" #include "parser/parse_type.h" +#include "parser/parse_oper.h" #include "parser/parser.h" #include "parser/scanner.h" #include "parser/scansup.h" @@ -51,17 +55,19 @@ #include "utils/syscache.h" #include "utils/numeric.h" #include +#include "pgstat.h" #include "executor/nodeFunctionscan.h" - #include "backend_parser/scanner.h" #include "hooks.h" #include "pltsql.h" #include "pl_explain.h" #include "catalog.h" +#include "dbcmds.h" #include "rolecmds.h" #include "session.h" #include "multidb.h" #include "tsql_analyze.h" +#include "table_variable_mvcc.h" #define TDS_NUMERIC_MAX_PRECISION 38 extern bool babelfish_dump_restore; @@ -69,46 +75,59 @@ extern char *babelfish_dump_restore_min_oid; extern bool pltsql_quoted_identifier; extern bool pltsql_ansi_nulls; + /***************************************** * Catalog Hooks *****************************************/ IsExtendedCatalogHookType PrevIsExtendedCatalogHook = NULL; +IsToastRelationHookType PrevIsToastRelationHook = NULL; +IsToastClassHookType PrevIsToastClassHook = 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 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); -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 void modify_insert_stmt(InsertStmt *stmt, Oid relid); +static inline bool is_identifier_char(unsigned char c); +static int find_attr_by_name_from_relation(Relation rd, const char *attname, bool sysColOK); +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); +static int getDefaultPosition(const List *default_positions, const ListCell *def_idx, int argPosition); +static List* replace_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, List *fargs); +static Node* optimize_explicit_cast(ParseState *pstate, Node *node); + +static ResTarget* make_restarget_from_colname(char * colName); +static void transform_pivot_clause(ParseState *pstate, SelectStmt *stmt); /***************************************** * 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); /***************************************** * Utility Hooks @@ -118,12 +137,20 @@ 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); +static bool pltsql_bbfCustomProcessUtility(ParseState *pstate, + PlannedStmt *pstmt, + const char *queryString, + ProcessUtilityContext context, + ParamListInfo params, QueryCompletion *qc); +extern void pltsql_bbfSelectIntoUtility(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, + QueryEnvironment *queryEnv, ParamListInfo params, QueryCompletion *qc); + /***************************************** * Executor Hooks *****************************************/ @@ -131,8 +158,16 @@ static void pltsql_ExecutorStart(QueryDesc *queryDesc, int eflags); static void pltsql_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once); static void pltsql_ExecutorFinish(QueryDesc *queryDesc); static void pltsql_ExecutorEnd(QueryDesc *queryDesc); +static bool pltsql_bbfViewHasInsteadofTrigger(Relation view, CmdType event); static bool plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo); +static bool bbf_check_rowcount_hook(int es_processed); + +static char *get_local_schema_for_bbf_functions(Oid proc_nsp_oid); +extern bool called_from_tsql_insert_exec(); +extern Datum pltsql_exec_tsql_cast_value(Datum value, bool *isnull, + Oid valtype, int32 valtypmod, + Oid reqtype, int32 reqtypmod); /***************************************** * Replication Hooks @@ -150,13 +185,15 @@ 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; 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 pre_transform_setop_tree_hook_type prev_pre_transform_setop_tree_hook = NULL; +static pre_transform_setop_sort_clause_hook_type prev_pre_transform_setop_sort_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; @@ -173,14 +210,33 @@ static ExecutorFinish_hook_type prev_ExecutorFinish = NULL; static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; static GetNewObjectId_hook_type prev_GetNewObjectId_hook = NULL; static inherit_view_constraints_from_table_hook_type prev_inherit_view_constraints_from_table = NULL; +static bbfViewHasInsteadofTrigger_hook_type prev_bbfViewHasInsteadofTrigger_hook = NULL; static detect_numeric_overflow_hook_type prev_detect_numeric_overflow_hook = NULL; static match_pltsql_func_call_hook_type prev_match_pltsql_func_call_hook = NULL; static insert_pltsql_function_defaults_hook_type prev_insert_pltsql_function_defaults_hook = NULL; +static replace_pltsql_function_defaults_hook_type prev_replace_pltsql_function_defaults_hook = NULL; static print_pltsql_function_arguments_hook_type prev_print_pltsql_function_arguments_hook = NULL; static planner_hook_type prev_planner_hook = NULL; static transform_check_constraint_expr_hook_type prev_transform_check_constraint_expr_hook = NULL; 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; +static bbfCustomProcessUtility_hook_type prev_bbfCustomProcessUtility_hook = NULL; +static bbfSelectIntoUtility_hook_type prev_bbfSelectIntoUtility_hook = NULL; +static sortby_nulls_hook_type prev_sortby_nulls_hook = NULL; +static optimize_explicit_cast_hook_type prev_optimize_explicit_cast_hook = NULL; +static table_variable_satisfies_visibility_hook_type prev_table_variable_satisfies_visibility = NULL; +static table_variable_satisfies_update_hook_type prev_table_variable_satisfies_update = NULL; +static table_variable_satisfies_vacuum_hook_type prev_table_variable_satisfies_vacuum = NULL; +static table_variable_satisfies_vacuum_horizon_hook_type prev_table_variable_satisfies_vacuum_horizon = NULL; +static drop_relation_refcnt_hook_type prev_drop_relation_refcnt_hook = NULL; +static set_local_schema_for_func_hook_type prev_set_local_schema_for_func_hook = NULL; +static bbf_get_sysadmin_oid_hook_type prev_bbf_get_sysadmin_oid_hook = NULL; +/* TODO: do we need to use variable to store hook value before transfrom pivot? No other function uses the same hook, should be redundant */ +static transform_pivot_clause_hook_type pre_transform_pivot_clause_hook = NULL; +static called_from_tsql_insert_exec_hook_type pre_called_from_tsql_insert_exec_hook = NULL; +static exec_tsql_cast_value_hook_type pre_exec_tsql_cast_value_hook = NULL; /***************************************** * Install / Uninstall @@ -202,15 +258,22 @@ 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; + prev_pre_transform_setop_tree_hook = pre_transform_setop_tree_hook; + pre_transform_setop_tree_hook = pre_transform_setop_tree; + prev_pre_transform_setop_sort_clause_hook = pre_transform_setop_sort_clause_hook; + pre_transform_setop_sort_clause_hook = pre_transform_setop_sort_clause; + post_transform_column_definition_hook = pltsql_post_transform_column_definition; post_transform_table_definition_hook = pltsql_post_transform_table_definition; @@ -264,6 +327,9 @@ InstallExtendedHooks(void) inherit_view_constraints_from_table_hook = preserve_view_constraints_from_base_table; TriggerRecuresiveCheck_hook = plsql_TriggerRecursiveCheck; + prev_bbfViewHasInsteadofTrigger_hook = bbfViewHasInsteadofTrigger_hook; + bbfViewHasInsteadofTrigger_hook = pltsql_bbfViewHasInsteadofTrigger; + prev_detect_numeric_overflow_hook = detect_numeric_overflow_hook; detect_numeric_overflow_hook = pltsql_detect_numeric_overflow; @@ -273,6 +339,9 @@ InstallExtendedHooks(void) prev_insert_pltsql_function_defaults_hook = insert_pltsql_function_defaults_hook; insert_pltsql_function_defaults_hook = insert_pltsql_function_defaults; + prev_replace_pltsql_function_defaults_hook = replace_pltsql_function_defaults_hook; + replace_pltsql_function_defaults_hook = replace_pltsql_function_defaults; + prev_print_pltsql_function_arguments_hook = print_pltsql_function_arguments_hook; print_pltsql_function_arguments_hook = print_pltsql_function_arguments; @@ -283,9 +352,62 @@ 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; + + 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; + + prev_bbfCustomProcessUtility_hook = bbfCustomProcessUtility_hook; + bbfCustomProcessUtility_hook = pltsql_bbfCustomProcessUtility; + + prev_bbfSelectIntoUtility_hook = bbfSelectIntoUtility_hook; + bbfSelectIntoUtility_hook = pltsql_bbfSelectIntoUtility; + + prev_sortby_nulls_hook = sortby_nulls_hook; + sortby_nulls_hook = sort_nulls_first; + + prev_table_variable_satisfies_update = table_variable_satisfies_update_hook; + table_variable_satisfies_update_hook = TVHeapTupleSatisfiesUpdate; + + prev_table_variable_satisfies_visibility = table_variable_satisfies_visibility_hook; + table_variable_satisfies_visibility_hook = TVHeapTupleSatisfiesVisibility; + + prev_table_variable_satisfies_vacuum = table_variable_satisfies_vacuum_hook; + table_variable_satisfies_vacuum_hook = TVHeapTupleSatisfiesVacuum; + + prev_table_variable_satisfies_vacuum_horizon = table_variable_satisfies_vacuum_horizon_hook; + table_variable_satisfies_vacuum_horizon_hook = TVHeapTupleSatisfiesVacuumHorizon; + + PrevIsToastRelationHook = IsToastRelationHook; + IsToastRelationHook = IsPltsqlToastRelationHook; + + PrevIsToastClassHook = IsToastClassHook; + IsToastClassHook = IsPltsqlToastClassHook; + + prev_drop_relation_refcnt_hook = drop_relation_refcnt_hook; + drop_relation_refcnt_hook = pltsql_drop_relation_refcnt_hook; + + prev_set_local_schema_for_func_hook = set_local_schema_for_func_hook; + set_local_schema_for_func_hook = get_local_schema_for_bbf_functions; + + prev_bbf_get_sysadmin_oid_hook = bbf_get_sysadmin_oid_hook; + bbf_get_sysadmin_oid_hook = get_sysadmin_oid; + + pre_transform_pivot_clause_hook = transform_pivot_clause_hook; + transform_pivot_clause_hook = transform_pivot_clause; + + prev_optimize_explicit_cast_hook = optimize_explicit_cast_hook; + optimize_explicit_cast_hook = optimize_explicit_cast; + + pre_called_from_tsql_insert_exec_hook = called_from_tsql_insert_exec_hook; + called_from_tsql_insert_exec_hook = called_from_tsql_insert_exec; + + pre_exec_tsql_cast_value_hook = exec_tsql_cast_value_hook; + exec_tsql_cast_value_hook = pltsql_exec_tsql_cast_value; } void @@ -298,10 +420,13 @@ 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 ; + pre_transform_insert_hook = prev_pre_transform_insert_hook; post_transform_insert_row_hook = prev_post_transform_insert_row_hook; + pre_transform_setop_tree_hook = prev_pre_transform_setop_tree_hook; + pre_transform_setop_sort_clause_hook = prev_pre_transform_setop_sort_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; @@ -320,24 +445,111 @@ UninstallExtendedHooks(void) ExecutorEnd_hook = prev_ExecutorEnd; GetNewObjectId_hook = prev_GetNewObjectId_hook; inherit_view_constraints_from_table_hook = prev_inherit_view_constraints_from_table; + bbfViewHasInsteadofTrigger_hook = prev_bbfViewHasInsteadofTrigger_hook; detect_numeric_overflow_hook = prev_detect_numeric_overflow_hook; match_pltsql_func_call_hook = prev_match_pltsql_func_call_hook; insert_pltsql_function_defaults_hook = prev_insert_pltsql_function_defaults_hook; + replace_pltsql_function_defaults_hook = prev_replace_pltsql_function_defaults_hook; print_pltsql_function_arguments_hook = prev_print_pltsql_function_arguments_hook; planner_hook = prev_planner_hook; transform_check_constraint_expr_hook = prev_transform_check_constraint_expr_hook; 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; + bbfCustomProcessUtility_hook = prev_bbfCustomProcessUtility_hook; + bbfSelectIntoUtility_hook = prev_bbfSelectIntoUtility_hook; + sortby_nulls_hook = prev_sortby_nulls_hook; + table_variable_satisfies_visibility_hook = prev_table_variable_satisfies_visibility; + table_variable_satisfies_update_hook = prev_table_variable_satisfies_update; + table_variable_satisfies_vacuum_hook = prev_table_variable_satisfies_vacuum; + table_variable_satisfies_vacuum_horizon_hook = prev_table_variable_satisfies_vacuum_horizon; + IsToastRelationHook = PrevIsToastRelationHook; + IsToastClassHook = PrevIsToastClassHook; + drop_relation_refcnt_hook = prev_drop_relation_refcnt_hook; + set_local_schema_for_func_hook = prev_set_local_schema_for_func_hook; + bbf_get_sysadmin_oid_hook = prev_bbf_get_sysadmin_oid_hook; + transform_pivot_clause_hook = pre_transform_pivot_clause_hook; + optimize_explicit_cast_hook = prev_optimize_explicit_cast_hook; + called_from_tsql_insert_exec_hook = pre_called_from_tsql_insert_exec_hook; } /***************************************** * Hook Functions *****************************************/ +static bool +pltsql_bbfCustomProcessUtility(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, + ParamListInfo params, QueryCompletion *qc) +{ + Node *parsetree = pstmt->utilityStmt; + + switch (nodeTag(parsetree)) + { + case T_CreateFunctionStmt: + { + return pltsql_createFunction(pstate, pstmt, queryString, context, params); + break; + } + case T_CreatedbStmt: + { + if (sql_dialect == SQL_DIALECT_TSQL) + { + create_bbf_db(pstate, (CreatedbStmt *) parsetree); + return true; + } + break; + } + case T_DropdbStmt: + { + if (sql_dialect == SQL_DIALECT_TSQL) + { + DropdbStmt *stmt = (DropdbStmt *) parsetree; + drop_bbf_db(stmt->dbname, stmt->missing_ok, false); + return true; + } + break; + } + case T_TransactionStmt: + { + if (NestedTranCount > 0 || (sql_dialect == SQL_DIALECT_TSQL && !IsTransactionBlockActive())) + { + PLTsqlProcessTransaction(parsetree, params, qc); + return true; + } + break; + } + default: + return false; + break; + } + return false; +} + +Oid prev_cache_collid; +pg_locale_t *prev_locale = NULL; + +pg_locale_t * +collation_cache_entry_hook_function(Oid collid, pg_locale_t *locale) +{ + if(!locale) + { + if(prev_locale && prev_cache_collid==collid) + { + return prev_locale; + } + } + else + { + prev_cache_collid = collid; + prev_locale = locale; + } + return NULL; +} static void pltsql_GetNewObjectId(VariableCache variableCache) { - Oid minOid; + Oid minOid; if (!babelfish_dump_restore || !babelfish_dump_restore_min_oid) return; @@ -354,10 +566,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); } @@ -426,6 +640,11 @@ pltsql_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, return; } + if ((count == 0 || (count > pltsql_rowcount && pltsql_rowcount != 0)) + && queryDesc->operation == CMD_SELECT + && sql_dialect == SQL_DIALECT_TSQL) + count = pltsql_rowcount; + if (prev_ExecutorRun) prev_ExecutorRun(queryDesc, direction, count, execute_once); else @@ -456,25 +675,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) @@ -482,16 +701,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; } } @@ -501,29 +725,156 @@ plsql_TriggerRecursiveCheck(ResultRelInfo *resultRelInfo) return false; } +/** + * Hook function to skip rewriting VIEW with base table if the VIEW has an instead of trigger + * Checks if view have an INSTEAD OF trigger at statement level + * If it does, we don't want to treat it as auto-updatable. + * Reference - src/backend/rewrite/rewriteHandler.c view_has_instead_trigger +*/ +static bool +pltsql_bbfViewHasInsteadofTrigger(Relation view, CmdType event) +{ + TriggerDesc *trigDesc = view->trigdesc; + + switch (event) + { + case CMD_INSERT: + if(trigDesc && trigDesc->trig_insert_instead_statement) + return true; + break; + case CMD_UPDATE: + if (trigDesc && trigDesc->trig_update_instead_statement) + return true; + break; + case CMD_DELETE: + if (trigDesc && trigDesc->trig_delete_instead_statement) + return true; + break; + default: + elog(ERROR, "unrecognized CmdType: %d", (int) event); + break; + } + return false; +} + +/* + * Wrapper function that calls the initilization function. + * Calls the pre function call hook on the procname + * before invoking the initilization function. Performing a + * system cache search in case fcinfo isnull for getting the procname + */ + +static char * +replace_with_underscore(const char *s) +{ + int i, + n = strlen(s); + char *s_copy = palloc(n + 1); + + s_copy[0] = '\0'; + strncat(s_copy, s, n); + + for (i = 0; i < n; i++) + { + if (s_copy[i] == '.') + s_copy[i] = '_'; + } + + return s_copy; +} + +void +pre_wrapper_pgstat_init_function_usage(const char *funcName) +{ + if ((pltsql_instr_plugin_ptr && + (*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); + + appendStringInfoString(&metricName, prefix); + appendStringInfoString(&metricName, funcname_edited); + + if (!(*pltsql_instr_plugin_ptr)->pltsql_instr_increment_func_metric(metricName.data)) + { + /* check with "unsupported" in prefix */ + prefix = "instr_unsupported_tsql_"; + + resetStringInfo(&metricName); + appendStringInfoString(&metricName, prefix); + appendStringInfoString(&metricName, funcname_edited); + (*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); + } +} + +void +pgstat_init_function_usage_wrapper(FunctionCallInfo fcinfo, + PgStat_FunctionCallUsage *fcusageptr, char *procname) +{ + + if (IsTransactionState()) + { + if(!(fcinfo->isnull)) + { + pre_wrapper_pgstat_init_function_usage((procname)); + } + else + { + HeapTuple proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fcinfo->flinfo->fn_oid)); + if (HeapTupleIsValid(proctup)) + { + Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(proctup); + pre_wrapper_pgstat_init_function_usage(NameStr(proc->proname)); + ReleaseSysCache(proctup); + } + } + } +} + 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; + /* 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()) { - /* 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 */ @@ -540,32 +891,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 @@ -575,6 +934,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) { @@ -590,14 +962,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); @@ -605,12 +979,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); @@ -622,12 +997,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; @@ -650,23 +1027,28 @@ handle_returning_qualifiers(Query *query, List *returningList, ParseState *pstat field1 = (Node *) linitial(cref->fields); qualifier = strVal(field1); - if ((command == CMD_INSERT && !strcmp(qualifier, "inserted")) - || (command == CMD_DELETE && !strcmp(qualifier, "deleted"))) + if (command == CMD_INSERT && !strcmp(qualifier, "inserted")) cref->fields = list_delete_first(cref->fields); + else if (command == CMD_DELETE && !strcmp(qualifier, "deleted")) + { + Assert(pstate->p_target_nsitem->p_names->aliasname); + linitial(cref->fields) = makeString(pstate->p_target_nsitem->p_names->aliasname); + } } } - 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); } @@ -678,22 +1060,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); @@ -710,18 +1094,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); } @@ -730,16 +1115,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); @@ -748,6 +1135,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 @@ -761,18 +1149,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); } @@ -791,23 +1180,29 @@ 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; + bool sq = false; + int i = 0; + char *original_name = NULL; + bool valid = false; + bool found_escaped_in_dq = false; + bool found_escaped_in_sq = false; /* check identifier is delimited */ Assert(start); @@ -815,14 +1210,22 @@ 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 */ + else if (start[0] == '\'') + sq = true; + ++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 */ - while (i < 258) + /* + * Reaching here implies of valid identifier. It means we can reach + * identifier's end in both the cases of single and multibyte characters. + * If the identifier is not valid, the scanner should have already reported a syntax error. + */ + while (true) { - char c = start[i]; + char c = start[i]; - if (!dq && !sqb) /* normal case */ + if (!dq && !sqb && !sq) /* normal case */ { /* please see {tsql_ident_cont} in scan-tsql-decl.l */ valid = is_identifier_char(c); @@ -838,9 +1241,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; } @@ -850,18 +1254,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), @@ -929,33 +1394,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; @@ -973,10 +1446,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)); @@ -985,7 +1464,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; @@ -1007,7 +1489,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); @@ -1020,36 +1502,38 @@ 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_varchartypoid = get_sys_varcharoid(); + 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); } } } static inline bool -is_identifier_char(char c) +is_identifier_char(unsigned 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; } @@ -1057,10 +1541,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) { @@ -1068,13 +1552,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++; @@ -1105,27 +1591,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; } } @@ -1142,39 +1630,103 @@ 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; - const char *colname_start; + int alias_len = 0; + const char *colname_start = NULL; const char *identifier_name = NULL; + int open_square_bracket = 0; + int double_quotes = 0; + const char *last_dot; 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. To prevent the server crash, res->location for queries + * with join statement should not be zero. */ - if (list_length(cref->fields) == 1 && - IsA(linitial(cref->fields), String)) + if (res->location != 0 && (list_length(cref->fields) == 1 && + IsA(linitial(cref->fields), String))) { identifier_name = strVal(linitial(cref->fields)); alias_len = strlen(identifier_name); colname_start = pstate->p_sourcetext + res->location; } + /* + * This condition will preserve the case of column name when there are more than + * one cref->fields. For instance, Queries like + * 1. select [database].[schema].[table].[column] from table. + * 2. select [schema].[table].[column] from table. + * 3. select [t].[column] from table as t + * Case 1: Handle the cases when column name is passed with no delimiters + * For example, select ABC from table + * Case 2: Handle the cases when column name is delimited with dq. + * In such cases, we are checking if no. of dq are even or not. When dq are odd, + * we are not tracing number of sqb and sq within dq. + * For instance, Queries like select "AF bjs'vs] " from table. + * Case 3: Handle the case when column name is delimited with sqb. When number of sqb + * are zero, it means we are out of sqb. + */ + else if(res->location != 0 && (list_length(cref->fields) > 1 && + IsA(llast(cref->fields), String))) + { + identifier_name = strVal(llast(cref->fields)); + alias_len = strlen(identifier_name); + colname_start = pstate->p_sourcetext + res->location; + last_dot = colname_start; + while(*colname_start != '\0') + { + if(open_square_bracket == 0 && *colname_start == '"') + { + double_quotes++; + } + /* To check how many open sqb are present in sourcetext. */ + else if(double_quotes % 2 == 0 && *colname_start == '[') + { + open_square_bracket++; + } + else if(double_quotes % 2 == 0 && *colname_start == ']') + { + open_square_bracket--; + } + /* + * last_dot pointer is to trace the last dot in the sourcetext, + * as last dot indicates the starting of column name. + */ + else if(open_square_bracket == 0 && double_quotes % 2 == 0 && *colname_start == '.') + { + last_dot = colname_start; + } + /* + * If there is no open sqb, there are even no. of sq or dq and colname_start is at + * space or comma, it means colname_start is at the end of column name. + */ + else if(open_square_bracket == 0 && double_quotes % 2 == 0 && (scanner_isspace(*colname_start) || *colname_start == ',')) + { + last_dot++; + colname_start = last_dot; + break; + } + colname_start++; + } + } } else if (res->name != NULL && res->name_location != -1) { @@ -1182,70 +1734,62 @@ pre_transform_target_entry(ResTarget *res, ParseState *pstate, alias_len = strlen(res->name); colname_start = pstate->p_sourcetext + res->name_location; } + else if (res->name == NULL && IsA(res->val, FuncCall) ){ + FuncCall *fc = (FuncCall *) res->val; + if (strcasecmp(strVal(llast(fc->funcname)), "identity_into_bigint") == 0) + { + // throw error if Select Into-identity function is called without a column name + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Incorrect syntax near the keyword 'INTO'"), + parser_errposition(pstate, res->location))); + } + } + /* + * Case 1 : Handle both singlebyte and multibyte aliases when delimited by + * square bracket(sqb) and double quoutes(dq) and single quotes(sq). + * For instance, queries like : SELECT 1 AS "您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选选装"; + * Case 2 : Preserve the case of aliases with ascii characters when there is no sq, sqb and dq. + * For instance, queries like: SELECT 1 AS ABCD; + * Case 3 : Handle both singlebyte and multibyte aliases whose length is + * more than or equals to 63 when not delimited by sq, sqb and dq. + * For example, queries like : SELECT 1 AS 您对您对您对您对您对您对您对您对您对您对您对您对您对; + */ 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; - const char *colname_end; - bool closing_quote_reached = false; + char *alias = palloc0(alias_len + 1); + const char *original_name = NULL; + int actual_alias_len = 0; - if (dq || sqb || sq) + /* To handle queries like SELECT (()) from */ + while(*colname_start != '\0' && (*colname_start == '(' || scanner_isspace(*colname_start))) { colname_start++; } - if (dq || sq) - { - - for (colname_end = colname_start; a < alias_len; colname_end++) - { - if (dq && *colname_end == '"') - { - if ((*(++colname_end) != '"')) - { - closing_quote_reached = true; - break; /* end of dbl-quoted identifier */ - } - } - else if (sq && *colname_end == '\'') - { - if ((*(++colname_end) != '\'')) - { - closing_quote_reached = true; - break; /* end of single-quoted identifier */ - } - } - - alias[a++] = *colname_end; - } + /* To extract the identifier name from the query.*/ + original_name = extract_identifier(colname_start); + actual_alias_len = strlen(original_name); - // Assert(a == alias_len); - } - else + /* Maximum alias_len can be 63 after truncation. If alias_len is smaller than actual_alias_len, + * this means Identifier is truncated and it's last 32 bytes would be MD5 hash. + */ + if(actual_alias_len > alias_len) { - colname_end = colname_start + alias_len; - memcpy(alias, colname_start, alias_len); - } + /* First 32 characters of original_name are assigned to alias. */ + memcpy(alias, original_name, (alias_len - 32)); - /* 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))) + /* Last 32 characters of identifier_name are assigned to alias, as actual alias is truncated. */ + memcpy(alias + (alias_len - 32), + identifier_name + (alias_len - 32), + 32); + alias[alias_len] = '\0'; + } + else /* Identifier is not truncated. */ { - memcpy(alias+(NAMEDATALEN-1)-32, - identifier_name+(NAMEDATALEN-1)-32, - 32); - alias[NAMEDATALEN] = '\0'; + memcpy(alias, original_name, actual_alias_len); } - res->name = alias; } } @@ -1256,23 +1800,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. */ @@ -1283,11 +1829,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)); @@ -1298,84 +1846,106 @@ 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); + /* Get physical schema name from logical schema name */ + char *physical_schema_name = get_physical_schema_name(get_cur_db_name(), schemaname); + /* Get relid using physical schema name and relname */ + relid = RangeVarGetRelid(makeRangeVar(physical_schema_name, relname, res->location), + NoLock, + true); + pfree(physical_schema_name); } - else if(relname) + else if (relname) { - relid = RelnameGetRelid(relname); + /* + * In case of schema name is not specified, To get the relid of table + * we will search for the table in schema of target relation. + */ + + /* Get physical schema name of target relation */ + char *physical_schema_name = get_namespace_name(RelationGetNamespace(pstate->p_target_relation)); + /* Get relid using physical schema name and relname */ + relid = RangeVarGetRelid(makeRangeVar(physical_schema_name, relname, res->location), + NoLock, + true); + pfree(physical_schema_name); } 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; } } @@ -1385,48 +1955,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); } } } @@ -1439,14 +2015,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)); } @@ -1457,64 +2033,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); @@ -1544,15 +2123,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; @@ -1561,11 +2140,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; @@ -1581,41 +2160,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) @@ -1625,14 +2218,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 @@ -1640,49 +2233,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, @@ -1695,9 +2288,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; @@ -1705,7 +2298,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; @@ -1722,15 +2315,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, @@ -1751,28 +2344,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) { @@ -1789,43 +2386,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); } @@ -1852,13 +2458,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); @@ -1868,10 +2474,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; } } @@ -1901,16 +2508,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 */ @@ -1962,21 +2570,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)); @@ -1990,7 +2600,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, ", "); } @@ -1999,22 +2609,25 @@ 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; - - if (prev_pre_transform_insert_hook) - (*prev_pre_transform_insert_hook) (stmt, relid); - - if (sql_dialect != SQL_DIALECT_TSQL) - return; + List *insert_col_list = NIL, + *temp_col_list; + char relkind = get_rel_relkind(relid); + + if(relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW) + { + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("The target '%s' of the OUTPUT INTO clause cannot be a view or common table expression.", stmt->relation->relname))); + } if (!output_into_insert_transformation) return; @@ -2029,19 +2642,26 @@ 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) { - col->name = NameStr(att->attname); + /* + * Do a deep copy of attname because tuple is a pointer + * to a shared_buffer page which is released when scan + * is ended. + */ + col->name = pstrdup(NameStr(att->attname)); + col->indirection = NIL; col->val = NULL; col->location = 1; @@ -2056,6 +2676,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 @@ -2069,13 +2707,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; @@ -2092,13 +2732,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)) { @@ -2109,12 +2749,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); @@ -2125,10 +2765,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) @@ -2136,11 +2776,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; @@ -2176,11 +2816,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)); @@ -2197,16 +2839,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) { @@ -2236,7 +2878,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 @@ -2244,19 +2886,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); } } @@ -2269,37 +2911,45 @@ 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; + { + if (partially_filled_numeric_block > 0) + { + int log_10 = (int) log10(partially_filled_numeric_block); // keep compiler happy + total_digit_count += log_10 + 1; + } + else + total_digit_count += 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); @@ -2318,17 +2968,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) @@ -2350,13 +3003,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)) { @@ -2366,8 +3019,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) @@ -2382,7 +3035,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); @@ -2397,23 +3050,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; @@ -2424,16 +3081,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) @@ -2445,12 +3101,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)); @@ -2460,6 +3117,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. */ @@ -2483,14 +3141,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(); @@ -2511,7 +3170,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)); @@ -2522,7 +3182,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); @@ -2563,7 +3223,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) { @@ -2593,9 +3253,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) { @@ -2628,8 +3287,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) { @@ -2637,8 +3296,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, @@ -2648,10 +3307,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)); @@ -2659,7 +3318,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++; @@ -2709,16 +3368,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); @@ -2793,11 +3452,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)) @@ -2807,12 +3466,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)); @@ -2828,7 +3487,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)); @@ -2846,21 +3505,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) { @@ -2905,6 +3564,105 @@ PlTsqlMatchNamedCall(HeapTuple proctup, int nargs, List *argnames, return true; } +static int getDefaultPosition(const List *default_positions, const ListCell *def_idx, int argPosition) +{ + int currPosition = intVal((Node *) lfirst(def_idx)); + while (currPosition != argPosition) + { + def_idx = lnext(default_positions, def_idx); + if (def_idx == NULL) + { + elog(ERROR, "not enough default arguments"); + return -1; + } + currPosition = intVal((Node *) lfirst(def_idx)); + } + return list_cell_number(default_positions, def_idx); +} + +/** + * @brief farg position default should get the corresponding default position value + * + * @param func_tuple + * @param defaults + * @param fargs + * @return List* + */ +static List* +replace_pltsql_function_defaults(HeapTuple func_tuple, List *defaults, List *fargs) + +{ + HeapTuple bbffunctuple; + + if (sql_dialect != SQL_DIALECT_TSQL) + return fargs; + + bbffunctuple = get_bbf_function_tuple_from_proctuple(func_tuple); + + if (HeapTupleIsValid(bbffunctuple)){ + Datum arg_default_positions; + bool isnull; + char *str; + List *default_positions = NIL, *ret = NIL; + ListCell *def_idx; + ListCell *lc; + int position,i,j; + + /* Fetch default positions */ + arg_default_positions = SysCacheGetAttr(PROCNSPSIGNATURE, + bbffunctuple, + Anum_bbf_function_ext_default_positions, + &isnull); + + if (isnull) + elog(ERROR, "not enough default arguments"); + + str =TextDatumGetCString(arg_default_positions); + default_positions = castNode(List, stringToNode(str)); + pfree(str); + + def_idx = list_head(default_positions); + i = 0; + + foreach(lc, fargs) + { + if (nodeTag((Node*)lfirst(lc)) == T_RelabelType && + nodeTag(((RelabelType*)lfirst(lc))->arg) == T_SetToDefault) + { + position = getDefaultPosition(default_positions, def_idx, i); + ret = lappend(ret, list_nth(defaults, position)); + } + else if (nodeTag((Node*)lfirst(lc)) == T_FuncExpr) + { + if(((FuncExpr*)lfirst(lc))->funcformat == COERCE_IMPLICIT_CAST && + nodeTag(linitial(((FuncExpr*)lfirst(lc))->args)) == T_SetToDefault) + { + // We'll keep the implicit cast function when it needs implicit cast + FuncExpr *funcExpr = (FuncExpr*)lfirst(lc); + List *newArgs = NIL; + position = getDefaultPosition(default_positions, def_idx, i); + newArgs = lappend(newArgs, list_nth(defaults, position)); + for (j = 1; j < list_length(funcExpr->args); ++j) + newArgs = lappend(newArgs, list_nth(funcExpr->args, j)); + funcExpr->args = newArgs; + ret = lappend(ret, funcExpr); + } + } + else ret = lappend(ret, lfirst(lc)); + ++i; + } + return ret; + + ReleaseSysCache(bbffunctuple); + } + else + { + elog(ERROR, "Can't use default in this function or procedure"); + } + + return fargs; +} + /* * insert_pltsql_function_defaults * Given a pg_proc heap tuple of a PL/tsql function and list of defaults, @@ -2923,8 +3681,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, @@ -2934,10 +3692,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)); @@ -2945,7 +3703,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); @@ -2957,8 +3715,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) @@ -3132,8 +3890,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); @@ -3178,7 +3936,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) @@ -3200,17 +3958,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(); @@ -3218,28 +3976,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; @@ -3255,42 +4016,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]))); } } @@ -3298,32 +4060,33 @@ 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 */ - if (!funcname || (strlen(funcname) != 9) || (strncasecmp(funcname, "openquery", 9) != 0)) - return; + if (!funcname || ((strlen(funcname) != 9 || strncasecmp(funcname, "openquery", 9) != 0) && + (strlen(funcname) != 18 || strncasecmp(funcname, "openquery_internal", 18) != 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); @@ -3337,54 +4100,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; + + if (sql_dialect != SQL_DIALECT_TSQL || output_update_transformation) + break; - target = pltsql_get_target_table(relation, delete_stmt->usingClause); + target = pltsql_get_target_table(relation, delete_stmt->usingClause); - break; - } + 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), @@ -3393,13 +4160,351 @@ 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; } 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) + { + AttrNumber attnum; + + attnum = (AttrNumber) attnameAttNum(rel, "dbid", false); + Assert(attnum != InvalidAttrNumber); + + if (nulls[attnum - 1]) + { + int16 dbid = getDbidForLogicalDbRestore(relid); + values[attnum - 1] = Int16GetDatum(dbid); + nulls[attnum - 1] = false; + } + } + + /* + * Populate owner column in babelfish_sysdatabases catalog table with + * SA of the current database. + */ + if (relid == sysdatabases_oid) + { + AttrNumber attnum; + + attnum = (AttrNumber) attnameAttNum(rel, "owner", false); + Assert(attnum != InvalidAttrNumber); + + if (nulls[attnum - 1]) + { + const char *owner = GetUserNameFromId(get_sa_role_oid(), false); + + values[attnum - 1] = CStringGetDatum(owner); + 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; +} + +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; + } +} + + +static char * +get_local_schema_for_bbf_functions(Oid proc_nsp_oid) +{ + HeapTuple tuple; + char *func_schema_name = NULL, + *new_search_path = NULL; + const char *func_dbo_schema, + *cur_dbname = get_cur_db_name(); + + tuple = SearchSysCache1(NAMESPACEOID, + ObjectIdGetDatum(proc_nsp_oid)); + if(HeapTupleIsValid(tuple)) + { + func_schema_name = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname); + func_dbo_schema = get_dbo_schema_name(cur_dbname); + + if(strcmp(func_schema_name, func_dbo_schema) != 0 + && strcmp(func_schema_name, "sys") != 0) + new_search_path = psprintf("%s, %s, \"$user\", sys, pg_catalog", + quote_identifier(func_schema_name), + quote_identifier(func_dbo_schema)); + + ReleaseSysCache(tuple); + } + return new_search_path; +} + +static ResTarget * +make_restarget_from_colname(char * colName) +{ + ResTarget *tempResTarget; + ColumnRef *tempColRef; + + tempResTarget = makeNode(ResTarget); + tempColRef = makeNode(ColumnRef); + tempColRef->location = -1; + tempColRef->fields = list_make1(makeString(colName)); + tempResTarget->name = NULL; + tempResTarget->name_location = -1; + tempResTarget->indirection = NIL; + tempResTarget->val = (Node *) tempColRef; + tempResTarget->location = -1; + return tempResTarget; +} + +static void +transform_pivot_clause(ParseState *pstate, SelectStmt *stmt) +{ + Query *temp_src_query; + List *temp_src_targetlist; + List *new_src_sql_targetist; + List *new_pivot_aliaslist; + List *src_sql_groupbylist; + List *src_sql_sortbylist; + char *pivot_colstr; + char *value_colstr; + ColumnRef *value_col; + TargetEntry *aggfunc_te; + RangeFunction *pivot_from_function; + RawStmt *s_sql; + RawStmt *c_sql; + MemoryContext oldContext; + MemoryContext tsql_outmost_context; + PLtsql_execstate *tsql_outmost_estat; + int nestlevel; + + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + new_src_sql_targetist = NULL; + new_pivot_aliaslist = NULL; + src_sql_groupbylist = NULL; + src_sql_sortbylist = NULL; + + /* transform temporary src_sql */ + temp_src_query = parse_sub_analyze((Node *) stmt->srcSql, pstate, NULL, + false, + false); + temp_src_targetlist = temp_src_query->targetList; + + /* Get pivot column str & value column str from parser result */ + pivot_colstr = stmt->pivotCol; + value_col = list_nth_node(ColumnRef, ((FuncCall *)((ResTarget *)stmt->aggFunc)->val)->args, 0); + value_colstr = list_nth_node(String, value_col->fields, 0)->sval; + + /* Get the targetList of the src table */ + for (int i = 0; i < temp_src_targetlist->length; i++) + { + ResTarget *tempResTarget; + ColumnDef *tempColDef; + TargetEntry *tempEntry = list_nth_node(TargetEntry, temp_src_targetlist, i); + + char *colName = tempEntry->resname; + + if (strcasecmp(colName, pivot_colstr) == 0 || strcasecmp(colName, value_colstr) == 0) + continue; + /* prepare src_sql's targetList */ + tempResTarget = make_restarget_from_colname(colName); + + if (new_src_sql_targetist == NULL) + new_src_sql_targetist = list_make1(tempResTarget); + else + new_src_sql_targetist = lappend(new_src_sql_targetist, tempResTarget); + + /* prepare pivot sql's alias_clause */ + tempColDef = makeColumnDef(colName, + ((Var *)tempEntry->expr)->vartype, + ((Var *)tempEntry->expr)->vartypmod, + ((Var *)tempEntry->expr)->varcollid + ); + + if (new_pivot_aliaslist == NULL) + new_pivot_aliaslist = list_make1(tempColDef); + else + new_pivot_aliaslist = lappend(new_pivot_aliaslist, tempColDef); + } + /* source_sql: non-pivot column + pivot colunm+ agg(value_col) */ + /* complete src_sql's targetList*/ + new_src_sql_targetist = lappend(new_src_sql_targetist, make_restarget_from_colname(pivot_colstr)); + new_src_sql_targetist = lappend(new_src_sql_targetist, (ResTarget *)stmt->aggFunc); + ((SelectStmt *)stmt->srcSql)->targetList = new_src_sql_targetist; + + /* complete src_sql's groupby*/ + for (int i = 0; i < new_src_sql_targetist->length - 1; i++) + { + A_Const *tempAConst = makeNode(A_Const); + SortBy *tempSortby = makeNode(SortBy); + tempAConst->val.ival.type = T_Integer; + tempAConst->val.ival.ival = i+1; + tempAConst->location = -1; + + tempSortby->node = (Node* )copyObject(tempAConst); + tempSortby->sortby_dir = 0; + tempSortby->sortby_nulls = 0; + tempSortby->useOp = NIL; + tempSortby->location = -1; + + if (src_sql_groupbylist == NULL) + { + src_sql_groupbylist = list_make1(tempAConst); + src_sql_sortbylist = list_make1(tempSortby); + } + else + { + src_sql_groupbylist = lappend(src_sql_groupbylist, tempAConst); + src_sql_sortbylist = lappend(src_sql_sortbylist, tempSortby); + } + } + ((SelectStmt *)stmt->srcSql)->groupClause = src_sql_groupbylist; + ((SelectStmt *)stmt->srcSql)->sortClause = src_sql_sortbylist; + + /* Transform the new src_sql & get the output type of that agg function*/ + temp_src_query = parse_sub_analyze((Node *) stmt->srcSql, pstate, NULL, + false, + false); + temp_src_targetlist = temp_src_query->targetList; + + /* asClause: non-pivot columns + value columns) */ + /* we can get the output data type of the aggregation function for later pivot columns */ + aggfunc_te = list_nth_node(TargetEntry, temp_src_targetlist, temp_src_targetlist->length - 1); + + /* complete pivo sql's alias_clause */ + /* Rewrite the fromClause in the outer select to have correct alias column name and datatype */ + pivot_from_function = list_nth_node(RangeFunction, stmt->fromClause, 0); + for(int i = 0; i < stmt->value_col_strlist->length; i++) + { + ColumnDef *tempColDef; + tempColDef = makeColumnDef((char *) list_nth(stmt->value_col_strlist, i), + ((Aggref *)aggfunc_te->expr)->aggtype, + -1, + ((Aggref *)aggfunc_te->expr)->aggcollid + ); + + if (new_pivot_aliaslist == NULL) + new_pivot_aliaslist = list_make1(tempColDef); + else + new_pivot_aliaslist = lappend(new_pivot_aliaslist, tempColDef); + } + + pivot_from_function->coldeflist = new_pivot_aliaslist; + + /* put the correct src_sql raw parse tree into the memory context for later use */ + tsql_outmost_estat = get_outermost_tsql_estate(&nestlevel); + tsql_outmost_context = tsql_outmost_estat->stmt_mcontext_parent; + if (!tsql_outmost_context) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("pivot outer context not found"))); + + oldContext = MemoryContextSwitchTo(tsql_outmost_context); + /* save rewrited sqls to global variable for later retrive */ + s_sql = makeNode(RawStmt); + c_sql = makeNode(RawStmt); + s_sql->stmt = (Node *) stmt->srcSql; + s_sql->stmt_location = 0; + s_sql->stmt_len = 0; + + c_sql->stmt = (Node *) stmt->catSql; + c_sql->stmt_location = 0; + c_sql->stmt_len = 0; + + tsql_outmost_estat->pivot_parsetree_list = lappend(tsql_outmost_estat->pivot_parsetree_list, list_make2(copyObject(s_sql), copyObject(c_sql))); + tsql_outmost_estat->pivot_number++; + MemoryContextSwitchTo(oldContext); +} + +static Node* optimize_explicit_cast(ParseState *pstate, Node *node) +{ + if (sql_dialect != SQL_DIALECT_TSQL) + return node; + if (node == NULL) + return NULL; + if (IsA(node, FuncExpr)) + { + FuncExpr *f = (FuncExpr *) node; + if (f->funcformat == COERCE_EXPLICIT_CAST){ + Node* arg = (Node*)linitial(f->args); + if (nodeTag(arg) == T_Var && + ((Var*) arg)->vartype == INT4OID && + f->funcresulttype == INT8OID) + return optimize_explicit_cast(pstate, linitial(f->args)); + } + } + else if (IsA(node, BoolExpr)) + { + BoolExpr *r = (BoolExpr *) node; + ListCell *l; + foreach (l , r->args) + { + optimize_explicit_cast(pstate, (Node*)lfirst(l)); + } + } + else if (IsA(node, OpExpr)) + { + OpExpr *opExpr = (OpExpr*) node; + Form_pg_operator form; + HeapTuple tuple; + Node* node = optimize_explicit_cast(pstate, linitial(opExpr->args)); + Node* result = NULL; + if (node != linitial(opExpr->args)) + { + char *opname; + + tuple = SearchSysCache1(OPEROID, ObjectIdGetDatum(opExpr->opno)); + if (!HeapTupleIsValid(tuple)) + return node; // no need to error out in here, stop transform and quite, keep the original node + form = (Form_pg_operator) GETSTRUCT(tuple); + + opname = NameStr(form->oprname); + if (strcmp(opname, "=") == 0) + { + result =(Node*)make_op(pstate, list_make1(makeString(opname)), node, lsecond(opExpr->args), pstate->p_last_srf, -1); + } + ReleaseSysCache(tuple); + if (result) + return result; + } + } + return node; +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/hooks.h b/contrib/babelfishpg_tsql/src/hooks.h index e68448d3a5..e4a1ff89cd 100644 --- a/contrib/babelfishpg_tsql/src/hooks.h +++ b/contrib/babelfishpg_tsql/src/hooks.h @@ -3,23 +3,32 @@ #include "postgres.h" #include "catalog/catalog.h" #include "parser/analyze.h" +#include "tcop/cmdtag.h" +#include "utils/pg_locale.h" extern IsExtendedCatalogHookType PrevIsExtendedCatalogHook; +extern IsToastRelationHookType PrevIsToastRelationHook; +extern IsToastClassHookType PrevIsToastClassHook; extern void InstallExtendedHooks(void); extern void UninstallExtendedHooks(void); +void pre_wrapper_pgstat_init_function_usage(const char *); +pg_locale_t *collation_cache_entry_hook_function(Oid ,pg_locale_t *); 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); + 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 void pltsql_bbfSelectIntoUtility(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, + QueryEnvironment *queryEnv, ParamListInfo params, QueryCompletion *qc); extern char *update_delete_target_alias; extern bool sp_describe_first_result_set_inprogress; #endif + diff --git a/contrib/babelfishpg_tsql/src/iterative_exec.c b/contrib/babelfishpg_tsql/src/iterative_exec.c index dc7d528f10..c5af008265 100644 --- a/contrib/babelfishpg_tsql/src/iterative_exec.c +++ b/contrib/babelfishpg_tsql/src/iterative_exec.c @@ -5,29 +5,30 @@ #include "pl_explain.h" #include "iterative_exec.h" #include "dynastack.h" +#include "table_variable_mvcc.h" /*************************************************************************************** * 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 +36,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 +95,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 +116,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 +127,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 +149,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 +163,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 +179,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 +195,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 +359,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 +372,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 +623,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 +672,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 +681,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 +690,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 +699,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 +739,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 +748,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 +760,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 +796,109 @@ 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_CHANGE_DBOWNER: 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 ALTER AUTHORIZATION statement 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_change_dbowner(estate, (PLtsql_stmt_change_dbowner *) stmt); + break; + case PLTSQL_STMT_GRANTSCHEMA: 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 GRANT DB 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_grantschema(estate, (PLtsql_stmt_grantschema *) stmt); + break; + case PLTSQL_STMT_FULLTEXTINDEX: 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 FULLTEXT INDEX 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_fulltextindex(estate, (PLtsql_stmt_fulltextindex *) stmt); + break; + 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"))); + } + 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"))); + } + 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"))); + } + exec_stmt_restore_ctx_partial(estate, (PLtsql_stmt_restore_ctx_partial *) stmt); + break; + case PLTSQL_STMT_DBCC: + exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); + break; + case PLTSQL_STMT_KILL: + exec_stmt_kill(estate, (PLtsql_stmt_kill *) 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 +908,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 +924,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 +939,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 +957,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 +973,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 +986,44 @@ 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) +bool +is_set_tran_isolation(PLtsql_stmt *stmt) +{ + if(stmt->cmd_type == PLTSQL_STMT_EXECSQL) + { + PLtsql_stmt_execsql *execsql = (PLtsql_stmt_execsql *) stmt; + return execsql->is_set_tran_isolation; + } + return false; +} + +static +void +record_error_state(PLtsql_execstate *estate) { if (exec_state_call_stack->error_data.error_estate == NULL) { @@ -950,7 +1042,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 +1051,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 +1061,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 +1093,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 +1104,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,21 +1141,24 @@ 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 */ if (IsTransactionBlockActive() && (last_error_mapping_failed || abort_transaction(estate, edata, override_flag))) { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN Mark transaction for rollback error mapping failed : %d", last_error_mapping_failed); + RESUME_INTERRUPTS(); AbortCurTransaction = true; } @@ -1071,7 +1171,9 @@ void handle_error(PLtsql_execstate *estate, /* In case of errors which terminate execution, let outer layer handle it */ if (last_error_mapping_failed || abort_execution(estate, edata, terminate_batch, override_flag) || ro_func) { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN Stop execution error mapping failed : %d current batch status : %d read only function : %d", last_error_mapping_failed, *terminate_batch, ro_func); + RESUME_INTERRUPTS(); FreeErrorData(edata); PG_RE_THROW(); } @@ -1088,31 +1190,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,15 +1231,14 @@ 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()) + if (!ro_func && !pltsql_disable_internal_savepoint && !is_batch_command(stmt) && IsTransactionBlockActive() && !is_set_tran_isolation(stmt)) { elog(DEBUG5, "TSQL TXN Start internal savepoint"); BeginInternalSubTransaction(NULL); @@ -1167,7 +1268,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,15 +1283,20 @@ 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 */ if (estate->tsql_trigger_flags & TSQL_TRIGGER_STARTED) EndCompositeTriggers(true); + /* Add current xid to a list of failed xids. */ + if (TransactionIdIsValid(GetCurrentTransactionIdIfAny())) + add_failed_transaction(GetCurrentTransactionIdIfAny()); + /* * Non TDS clients will just throw the error in all cases */ @@ -1195,15 +1304,18 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, { if (internal_sp_started) { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN PG semantics : Rollback internal savepoint"); RollbackAndReleaseCurrentSubTransaction(); MemoryContextSwitchTo(cur_ctxt); + RESUME_INTERRUPTS(); CurrentResourceOwner = oldowner; } else if (!IsTransactionBlockActive()) { if (is_part_of_pltsql_trycatch_block(estate)) { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN PG semantics : Rollback current transaction"); HoldPinnedPortals(); SPI_setCurrentInternalTxnMode(true); @@ -1211,11 +1323,14 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, StartTransactionCommand(); SPI_setCurrentInternalTxnMode(false); MemoryContextSwitchTo(cur_ctxt); + RESUME_INTERRUPTS(); } } else { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN PG semantics : Mark transaction for rollback"); + RESUME_INTERRUPTS(); AbortCurTransaction = true; } /* Recreate evaluation context in case needed */ @@ -1243,54 +1358,61 @@ int dispatch_stmt_handle_error(PLtsql_execstate *estate, before_lxid == MyProc->lxid && before_subtxn_id == GetCurrentSubTransactionId()) { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback internal savepoint"); /* Rollback internal savepoint if it is current savepoint */ RollbackAndReleaseCurrentSubTransaction(); MemoryContextSwitchTo(cur_ctxt); + RESUME_INTERRUPTS(); CurrentResourceOwner = oldowner; } 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 */ - + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback current transaction"); /* Hold portals to make sure that cursors work */ HoldPinnedPortals(); AbortCurrentTransaction(); StartTransactionCommand(); MemoryContextSwitchTo(cur_ctxt); + RESUME_INTERRUPTS(); } 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 */ + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback internal transaction"); HoldPinnedPortals(); pltsql_rollback_txn(); estate->tsql_trigger_flags &= ~TSQL_TRAN_STARTED; MemoryContextSwitchTo(cur_ctxt); + RESUME_INTERRUPTS(); } /* - * 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)) { + HOLD_INTERRUPTS(); elog(DEBUG1, "TSQL TXN TSQL semantics : Rollback implicit transaction"); pltsql_rollback_txn(); MemoryContextSwitchTo(cur_ctxt); + RESUME_INTERRUPTS(); } estate->impl_txn_type = PLTSQL_IMPL_TRAN_OFF; @@ -1303,53 +1425,64 @@ 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 */ + /* Set the current Statement Start time at satement level and not at batch. */ + SetCurrentStatementStartTimestamp(); + + /* + * 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 +1491,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 +1515,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 +1539,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 +1570,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 +1583,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 +1610,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 +1623,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 +1645,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 +1664,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 +1684,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 +1729,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 +1748,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 +1792,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 +1829,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 +1844,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 +1854,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 +1873,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 +1902,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 +1927,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 +1949,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 +1980,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 +2012,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..451840e5c1 100644 --- a/contrib/babelfishpg_tsql/src/linked_servers.c +++ b/contrib/babelfishpg_tsql/src/linked_servers.c @@ -10,6 +10,7 @@ #include "pltsql.h" #include "linked_servers.h" #include "guc.h" +#include "catalog.h" #define NO_CLIENT_LIB_ERROR() \ ereport(ERROR, \ @@ -21,28 +22,30 @@ #define LINKED_SERVER_DEBUG_FINER(...) elog(DEBUG2, __VA_ARGS__) PG_FUNCTION_INFO_V1(openquery_internal); +PG_FUNCTION_INFO_V1(sp_testlinkedserver_internal); #ifdef ENABLE_TDS_LIB #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 bool isQueryTimeout; 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 +53,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 +79,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 +108,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; @@ -123,16 +130,13 @@ remove_substr(char *src, const char *substr) return src; } -/* - * Handle any error encountered in TDS client library itself - */ -static int -linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error, int os_error, char *db_err_str, char *os_err_str) +static StringInfoData +construct_err_string (int severity, int db_error, int os_error, char *db_err_str, char *os_err_str) { 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'; } @@ -162,9 +166,29 @@ linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error appendStringInfo(&buf, "Level: %i", severity); + return buf; +} + +/* + * Handle any error encountered in TDS client library itself + */ +static int +linked_server_err_handler(LinkedServerProcess lsproc, int severity, int db_error, int os_error, char *db_err_str, char *os_err_str) +{ + StringInfoData buf; + + buf = construct_err_string(severity, db_error, os_error, db_err_str, os_err_str); + + /* when the query times out we need to return LS_INT_CANCEL */ + if (db_error == SYBETIME) + { + isQueryTimeout = true; + return LS_INT_CANCEL; + } + ereport(ERROR, (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), - errmsg("%s", buf.data))); + errmsg("%s", buf.data))); return LS_INT_CANCEL; } @@ -176,8 +200,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 +215,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 +223,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 +251,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 +270,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 +288,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 +324,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 +351,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 +361,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 +384,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 +402,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 +423,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 +440,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 +501,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 +519,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 +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 + VARHDRSZ; else - return (datalen/4) + VARHDRSZ; + return (datalen / 4) + VARHDRSZ; } case TSQL_NCHAR_X: case TSQL_NVARCHAR_X: @@ -613,16 +651,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 +684,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 +706,49 @@ 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, bool isTesting) { /* 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; + int query_timeout = 0; + int connect_timeout = 0; - 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 +758,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,11 +797,21 @@ 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) + )); } + /* fetch connect timeout from the servername */ + connect_timeout = get_timeout_from_server_name(servername, Anum_bbf_servers_def_connect_timeout); + + /* + * fetch query timeout from the servername + * Don't fetch when testing connection as query timeout is not required + */ + if(!isTesting) + query_timeout = get_timeout_from_server_name(servername, Anum_bbf_servers_def_query_timeout); + LINKED_SERVER_SET_APP(login); LINKED_SERVER_SET_VERSION(login); @@ -770,12 +823,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); @@ -787,21 +840,33 @@ linked_server_establish_connection(char* servername, LinkedServerProcess *lsproc LINKED_SERVER_SET_DBNAME(login, database); } + if(connect_timeout > 0) + { + LINKED_SERVER_SET_CONNECT_TIMEOUT(connect_timeout); + } + LINKED_SERVER_DEBUG("LINKED SERVER: Connecting to remote server \"%s\"", data_src); *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); + if(!isTesting && query_timeout > 0) + { + LINKED_SERVER_SET_QUERY_TIMEOUT(query_timeout); + } + LINKED_SERVER_DEBUG("LINKED SERVER: Connected to remote server"); } PG_CATCH(); { + HOLD_INTERRUPTS(); LINKED_SERVER_DEBUG("LINKED SERVER: Failed to establish connection to remote server due to error"); + RESUME_INTERRUPTS(); PG_RE_THROW(); } @@ -809,24 +874,27 @@ 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; + LinkedServerProcess lsproc = NULL; PG_TRY(); { LINKED_SERVER_RETCODE erc; StringInfoData buf; - int colcount; + int colcount; - linked_server_establish_connection(linked_server, &lsproc); + linked_server_establish_connection(linked_server, &lsproc, false); - /* 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 +904,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 +914,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 +928,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 +938,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 +1050,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 +1095,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) @@ -1043,8 +1123,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(); } @@ -1053,13 +1136,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; @@ -1068,9 +1151,10 @@ openquery_imp(PG_FUNCTION_ARGS) PG_TRY(); { + isQueryTimeout = false; 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_establish_connection(PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)), &lsproc, false); LINKED_SERVER_DEBUG("LINKED SERVER: (OPENQUERY) - Writing the following query to LinkedServerProcess struct: %s", query); @@ -1078,33 +1162,47 @@ 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"); /* Execute the query on remote server */ if (LINKED_SERVER_EXEC_QUERY(lsproc) == FAIL) + { + if (isQueryTimeout) + { + StringInfoData buf; + isQueryTimeout = false; + buf = construct_err_string(6, 20003, 0, "server connection timed out", "Success"); + ereport(ERROR, + (errcode(ERRCODE_FDW_UNABLE_TO_CREATE_EXECUTION), + errmsg("%s", buf.data))); + } 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 +1210,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 +1273,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) @@ -1201,21 +1302,24 @@ 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); } 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 +1336,44 @@ openquery_internal(PG_FUNCTION_ARGS) #else NO_CLIENT_LIB_ERROR(); #endif - return (Datum)0; + return (Datum) 0; } + +Datum +sp_testlinkedserver_internal(PG_FUNCTION_ARGS) +{ +#ifdef ENABLE_TDS_LIB + char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); + + LinkedServerProcess lsproc = NULL; + + if (servername == NULL) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("@servername parameter cannot be NULL"))); + + PG_TRY(); + { + remove_trailing_spaces(servername); + + linked_server_establish_connection(servername, &lsproc, true); + } + PG_FINALLY(); + { + if (lsproc) + { + LINKED_SERVER_DEBUG("LINKED SERVER: (CONNECTION TEST) - Closing connections to remote server"); + LINKED_SERVER_EXIT(); + } + } + PG_END_TRY(); + + if(servername) + pfree(servername); +#else + NO_CLIENT_LIB_ERROR(); +#endif + PG_RETURN_VOID(); + +} + diff --git a/contrib/babelfishpg_tsql/src/linked_servers.h b/contrib/babelfishpg_tsql/src/linked_servers.h index 2e56678171..f2cf1142a7 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) @@ -101,6 +101,8 @@ typedef DBPROCESS *LinkedServerProcess; #define LINKED_SERVER_SET_APP(login) DBSETLAPP(login, "babelfish_linked_server") #define LINKED_SERVER_SET_VERSION(login) DBSETLVERSION(login, DBVERSION_74) #define LINKED_SERVER_SET_DBNAME(login, dbname) DBSETLDBNAME(login, dbname) +#define LINKED_SERVER_SET_QUERY_TIMEOUT(timeout) dbsettime(timeout) +#define LINKED_SERVER_SET_CONNECT_TIMEOUT(timeout) dbsetlogintime(timeout) #define LS_NTBSTRINGBING NTBSTRINGBIND #define LS_INTBIND INTBIND @@ -139,6 +141,8 @@ typedef int *LinkedServerProcess; #define LINKED_SERVER_SET_APP(login) ((void)0) #define LINKED_SERVER_SET_VERSION(login) ((void)0) #define LINKED_SERVER_SET_DBNAME(login, dbname) ((void)0) +#define LINKED_SERVER_SET_QUERY_TIMEOUT(timeout) ((void)0) +#define LINKED_SERVER_SET_CONNECT_TIMEOUT(timeout) ((void)0) #define LS_NTBSTRINGBING 0 #define LS_INTBIND 0 diff --git a/contrib/babelfishpg_tsql/src/multidb.c b/contrib/babelfishpg_tsql/src/multidb.c index edaa5bcb47..fae2902d4b 100644 --- a/contrib/babelfishpg_tsql/src/multidb.c +++ b/contrib/babelfishpg_tsql/src/multidb.c @@ -19,19 +19,25 @@ /* 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); +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); @@ -42,7 +48,8 @@ static bool rewrite_relation_walker(Node *node, void *context); 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()) @@ -60,7 +67,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) @@ -69,565 +76,612 @@ 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: - { - /* 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: + case ACL_TARGET_OBJECT: { - rewrite_rangevar_list(grant->objects); - break; - } - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - { - 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; + + rewrite_rangevar(create->relation); - switch (nodeTag(element)) + 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; - - /* handle type */ - rewrite_plain_name(typename->names); + TruncateStmt *truncate = (TruncateStmt *) stmt; - /* 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: + { + 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(); + + 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; } @@ -639,32 +693,195 @@ 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; + + /* + * 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; } 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); +} + +/* + * 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; } /************************************************************* @@ -673,42 +890,43 @@ rewrite_relation_walker(Node *node, void *context) 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; } @@ -720,7 +938,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); @@ -730,15 +948,61 @@ 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); } } } +static void +set_schemaname_dbo_to_sys(RangeVar *rv) +{ + /* + * list_of_dbo_catalog + * Contains the list of sys% views which are not database specific + * + * list_of_dbo_catalog_not_supported_for_cross_db + * Contains the list of sys% views which are database specific + * + * NOTE: While adding the sys% views to list check whether view is an database specific or not. + * + */ + char* list_of_dbo_catalog[6]= {"sysprocesses", "syscharsets", "sysconfigures", "syscurconfigs", "syslanguages", "syslogins"}; + char* list_of_dbo_catalog_not_supported_for_cross_db[6]= {"syscolumns", "sysforeignkeys", "sysindexes", "sysobjects", "systypes", "sysusers"}; + if (rv->schemaname && strcmp(rv->schemaname, "dbo") == 0) + { + for (int i = 0; i < (sizeof(list_of_dbo_catalog)/sizeof(list_of_dbo_catalog[0])); i++) + { + if(rv->relname && strcmp(rv->relname, list_of_dbo_catalog[i]) == 0) + { + rv->schemaname = pstrdup("sys"); + break; + } + } + for (int i = 0; i < (sizeof(list_of_dbo_catalog_not_supported_for_cross_db)/sizeof(list_of_dbo_catalog_not_supported_for_cross_db[0])); 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) { @@ -751,40 +1015,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; } @@ -793,7 +1066,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))) @@ -804,26 +1077,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; } @@ -832,8 +1106,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); @@ -844,11 +1118,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); } } @@ -856,11 +1131,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); } } @@ -868,7 +1144,7 @@ rewrite_objectwithargs_list(List *objs) static void rewrite_plain_name_list(List *names) { - ListCell *cell; + ListCell *cell; foreach(cell, names) { @@ -879,11 +1155,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); } } @@ -891,23 +1168,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); @@ -922,9 +1201,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(); @@ -947,9 +1226,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; @@ -964,11 +1243,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; @@ -977,9 +1260,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); @@ -990,15 +1274,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; @@ -1007,6 +1292,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); } @@ -1031,9 +1317,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; @@ -1055,13 +1341,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))) @@ -1075,6 +1362,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 */ @@ -1086,19 +1374,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; } } @@ -1106,19 +1395,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; } } @@ -1126,73 +1416,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)); } @@ -1200,7 +1497,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"); @@ -1208,7 +1506,7 @@ bool is_user_database_singledb(const char *dbname) /************************************************************* - * Helper Functions + * Helper Functions *************************************************************/ /* in-place truncate identifiers if needded */ @@ -1226,21 +1524,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + 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 bf9a3ff929..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); @@ -29,5 +30,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/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..af89f2f5a1 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. @@ -162,6 +166,7 @@ pltsql_compile(FunctionCallInfo fcinfo, bool forValidator) PLtsql_func_hashkey hashkey; bool function_valid = false; bool hashkey_valid = false; + bool function_in_use = false; /* * Lookup the pg_proc tuple by Oid; we'll need it in any case @@ -193,14 +198,19 @@ 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 { /* * Nope, so remove it from hashtable and try to drop associated * storage (if not done already). + * Check whether function is in use or not before deleting it, if + * function is not in use - its memory context will be freed. + * PLtsql_function struct itself could have been allocated in the same + * context, so we avoid accessing struct fields after the delete call. */ + function_in_use = function->use_count != 0; delete_function(function); /* @@ -217,7 +227,7 @@ pltsql_compile(FunctionCallInfo fcinfo, bool forValidator) * a replacement has already been made, so go back and recheck the * hashtable. */ - if (function->use_count != 0) + if (function_in_use) { function = NULL; if (!hashkey_valid) @@ -311,10 +321,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 +368,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 +431,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."))); @@ -450,24 +465,25 @@ do_compile(FunctionCallInfo fcinfo, PLtsql_type *argdtype; PLtsql_variable *argvariable; PLtsql_nsitem_type argitemtype; + int typmod = 0; /* Create $n name for variable */ snprintf(buf, sizeof(buf), "$%d", i + 1); /* 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) @@ -481,11 +497,17 @@ do_compile(FunctionCallInfo fcinfo, function->is_mstvf = true; } - /* Create datatype info */ + /* + * Create datatype info. + * typmods array has length procStruct->pronargs and numargs >= procStruct->pronargs, + * (See Assert in get_func_arg_info()) + * Pass in typmods[i] while we are not out of bounds, otherwise pass in -1. + */ + typmod = (typmods && i < procStruct->pronargs) ? typmods[i] : -1; argdtype = pltsql_build_datatype(argtypeid, - (typmods ? typmods[i] : -1), - function->fn_input_collation, - NULL); + typmod, + function->fn_input_collation, + NULL); /* Disallow pseudotype argument */ /* (note we already replaced polymorphic types) */ @@ -501,18 +523,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 +570,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 +596,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 +677,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 +689,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 +724,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 +849,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 +884,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 +913,7 @@ do_compile(FunctionCallInfo fcinfo, else { report_antlr_error(result); - parse_rc = 1; /* invalid input */ + parse_rc = 1; /* invalid input */ } } @@ -900,16 +925,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 +979,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 +1016,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 +1120,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 +1169,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 +1183,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 +1194,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 +1212,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 +1223,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 +1247,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 +1275,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 +1289,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 +1337,7 @@ pltsql_compile_inline(char *proc_source, InlineCodeBlockArgs *args) } PG_END_TRY(); destroy_compile_context(cmpl_ctx); - + return function; } @@ -1337,11 +1359,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 +1403,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 +1552,36 @@ 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; 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(); { @@ -1560,9 +1589,11 @@ pltsql_post_expand_star(ParseState *pstate, ColumnRef *cref, List *l) } PG_CATCH(); { + HOLD_INTERRUPTS(); elog(LOG, "Cache lookup failed in pltsql_post_expand_star for attribute %d of relation %u", - attnum, relid); + attnum, relid); attopts = (Datum) 0; + RESUME_INTERRUPTS(); } PG_END_TRY(); if (!attopts) @@ -1572,7 +1603,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++) { @@ -1582,9 +1613,7 @@ pltsql_post_expand_star(ParseState *pstate, ColumnRef *cref, List *l) /* * We found the original name; rewrite it as bbf_original_name */ - bbf_original_name = &optstr[18]; - bbf_original_name[strlen(te->resname)] = '\0'; - te->resname = pstrdup(bbf_original_name); + te->resname = pnstrdup((char *) &optstr[18], strlen(te->resname)); break; } } @@ -1604,8 +1633,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 +1751,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 +1843,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 +1871,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 +1880,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 +1893,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 +1934,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 +1954,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 +2014,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 +2036,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 +2092,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 +2171,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 +2286,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 +2321,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 +2335,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 +2361,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 +2373,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 +2385,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 +2393,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 +2414,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 +2581,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 +2837,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 +3016,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 +3032,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 +3112,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 +3123,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 +3134,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 +3161,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 +3173,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 +3198,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 +3231,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..4e948a0be0 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec-2.c +++ b/contrib/babelfishpg_tsql/src/pl_exec-2.c @@ -4,13 +4,18 @@ #include "funcapi.h" #include "access/table.h" +#include "access/attmap.h" #include "catalog/namespace.h" +#include "catalog/pg_attribute.h" #include "catalog/pg_language.h" #include "commands/proclang.h" #include "executor/tstoreReceiver.h" #include "nodes/parsenodes.h" #include "utils/acl.h" +#include "storage/lmgr.h" +#include "storage/procarray.h" #include "pltsql_bulkcopy.h" +#include "table_variable_mvcc.h" #include "catalog.h" #include "dbcmds.h" @@ -30,102 +35,112 @@ 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_kill(PLtsql_execstate *estate, PLtsql_stmt_kill *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_grantschema(PLtsql_execstate *estate, PLtsql_stmt_grantschema *stmt); +static int exec_stmt_fulltextindex(PLtsql_execstate *estate, PLtsql_stmt_fulltextindex *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_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt); 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); +bool called_from_tsql_insert_exec(void); +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); extern void disable_sp_cursor_find_param_hook(void); extern void add_sp_cursor_param(char *name); extern void reset_sp_cursor_params(); +extern char *construct_unique_index_name(char *index_name, char *relation_name); +extern const char *gen_schema_name_for_fulltext_index(const char *schema_name); 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); +void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt); +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; +bool called_from_tsql_insert_execute = 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; +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 */ static Node *get_underlying_node_from_implicit_casting(Node *n, NodeTag underlying_nodetype); - + /* * The pltsql_proc_return_code global variable is used to record the * 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 +155,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 +179,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) { @@ -170,11 +187,15 @@ exec_tsql_stmt(PLtsql_execstate *estate, PLtsql_stmt *stmt, PLtsql_stmt *save_es rc = exec_stmt_print(estate, (PLtsql_stmt_print *) stmt); break; + case PLTSQL_STMT_KILL: + rc = exec_stmt_kill(estate, (PLtsql_stmt_kill *) stmt); + 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 +219,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 +240,162 @@ 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; + case PLTSQL_STMT_DBCC: + rc = exec_stmt_dbcc(estate, (PLtsql_stmt_dbcc *) stmt); + break; default: estate->err_stmt = save_estmt; elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); } - + return rc; } +static int +exec_stmt_kill(PLtsql_execstate *estate, PLtsql_stmt_kill *stmt) +{ + PGPROC *proc; + Oid sysadmin_oid = get_role_oid("sysadmin", false); /* We should really use BABELFISH_SYSADMIN in tds_int.h . */ + int spid = -1; + Assert(stmt->spid); + spid = stmt->spid; + + if (pltsql_explain_only) + { + StringInfoData query; + + initStringInfo(&query); + appendStringInfo(&query, "KILL "); + appendStringInfoString(&query, psprintf("%d", spid)); + append_explain_info(NULL, query.data); + pfree(query.data); + return PLTSQL_RC_OK; + } + + /* Do not allow to run KILL inside a transaction. */ + if (IsTransactionBlockActive()) + { + ereport(ERROR, + (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), + errmsg("%s command cannot be used inside user transactions.", "KILL"))); + } + + /* Require that the user has 'sysadmin' role. */ + if (!has_privs_of_role(GetSessionUserId(), sysadmin_oid)) + { + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("User does not have permission to use the KILL statement"))); + } + + /* + * SPID value must be a positive number; the T-SQL grammar allows only a non-negative number to be specified. + * Yet, play it safe and test for it. + * A variable or expression is not allowed and caught in the parser. + * All other variants of T-SQL KILL are not supported, this is caught in the parser. + */ + if (spid <= 0) + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Session ID %d is not valid", spid))); + } + + /* Verify it is an actually existing process; otherwise we might just be killing any process on the host. */ + proc = BackendPidGetProc(spid); + if (proc == NULL) + { + ereport(ERROR, + errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Process ID %d is not an active process ID", spid)); + } + + /* Do not kill ourselves. */ + if (spid == MyProcPid) + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Cannot use KILL to kill your own process."))); + } + + /* + * Verify this is a TDS connection, not a PG connection: we should not kill PG connections from T-SQL. + * This can be verified by checking the session to be present in sys.dm_exec_sessions or + * sys.dm_exec_connections, which contains T-SQL connections only + * (unlike sys.syprocesses which also contains PG connections since this view is also + * based on pg_locks and pg_stat_activity). + */ + { + uint64 nrRows = 0; + char *query = psprintf("SELECT DISTINCT 1 FROM sys.dm_exec_sessions WHERE session_id = %d ", spid); + int rc = SPI_execute(query, true, 1); + pfree(query); + + /* Copy #rows before cleaning up below. */ + nrRows = SPI_processed; + + /* + * We're only interested in the #rows found: 0 or non-zero; we don't care about + * the actual result set. So we can clean up already now. + */ + SPI_freetuptable(SPI_tuptable); + + if (rc != SPI_OK_SELECT) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("SPI_execute failed: %s", SPI_result_code_string(rc)))); + } + + /* + * 1 row found: TDS connection + * 0 rows found: PG connection (since the connection was found to exist above) + */ + if (nrRows == 0) + { + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("Process ID %d is not an active process ID for a TDS connection", spid))); + } + } + + /* + * All validations passed, send the signal to the backend process. + * This is basically the same as what pg_terminate_backend() does.. + */ + if (kill(spid, SIGTERM)) + { + /* KILL is a best-effort attempt, so proceed rather than abort in case it does not work out. */ + ereport(WARNING, + (errmsg("Could not send signal to process %d: %m", spid))); + } + + /* Send no further message to the client, irrespective of the result. */ + /* KILL resets the rowcount. */ + exec_set_rowcount(0); + + return PLTSQL_RC_OK; +} + 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 +418,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 +432,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 +441,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 +453,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 +478,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 +503,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 +515,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 +536,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 +560,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 +600,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 +624,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 +645,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 +655,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 +708,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 +721,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 +738,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 +759,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 +810,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 +875,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 +909,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 +930,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), @@ -803,17 +960,18 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) PLtsql_row *row; int nfields; int i; - ListCell *lc; + int relativeArgIndex; + ListCell *lc; 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"); @@ -865,19 +1023,44 @@ exec_stmt_exec(PLtsql_execstate *estate, PLtsql_stmt_exec *stmt) i = 0; foreach(lc, funcargs) { - Node *n = lfirst(lc); + Node *n = lfirst(lc); if (argmodes && (argmodes[i] == PROARGMODE_INOUT || argmodes[i] == PROARGMODE_OUT)) { + ListCell *paramcell; + relativeArgIndex = 0; + + /* + * The order of arguments in procedure call might be different from the order of + * arguments in the funcargs. + * For each argument in funcargs, find corresponding argument in stmt->params. + */ + foreach(paramcell, stmt->params) + { + tsql_exec_param *p = (tsql_exec_param *) lfirst(paramcell); + if (argnames[i] && p->name && pg_strcasecmp(argnames[i], p->name) == 0) + break; + relativeArgIndex++; + } + + /* + * If argnames[i] is not found in stmt->params, i th parameter is passed in + * 'value' format instead of '@name = value'. In this case, argnames[i] should be mapped + * to i th element in stmt->params. + */ + if (relativeArgIndex >= stmt->paramno) + relativeArgIndex = i; + if (parammodes && - parammodes[i] != PROARGMODE_INOUT && - parammodes[i] != PROARGMODE_OUT) + parammodes[relativeArgIndex] != PROARGMODE_INOUT && + parammodes[relativeArgIndex] != 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 +1074,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 +1094,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 +1155,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 +1181,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 +1190,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 +1202,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 +1225,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 +1254,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 +1283,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 +1333,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 +1357,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 +1377,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; @@ -1194,10 +1393,13 @@ exec_stmt_decl_table(PLtsql_execstate *estate, PLtsql_stmt_decl_table *stmt) if (var->tbltypeid == InvalidOid) var->tbltypeid = TypenameGetTypid(tblname); var->need_drop = true; + + init_failed_transactions_map(); } 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 +1418,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 +1429,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 +1448,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 +1504,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 +1516,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 +1534,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 +1568,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 +1579,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 +1590,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 +1607,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(); @@ -1416,15 +1621,14 @@ execute_batch(PLtsql_execstate *estate, char *batch, InlineCodeBlockArgs *args, PG_CATCH(); { /* Delete temporary tables as ENR */ - ENRDropTempTables(currentQueryEnv); - remove_queryEnv(); + pltsql_remove_current_query_env(); + PG_RE_THROW(); } PG_END_TRY(); /* Delete temporary tables as ENR */ - ENRDropTempTables(currentQueryEnv); - remove_queryEnv(); + pltsql_remove_current_query_env(); after_lxid = MyProc->lxid; @@ -1450,7 +1654,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 +1669,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 +1688,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 +1711,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 +1730,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 +1749,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; - } + { + 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; + { + 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"))); + 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"))); + 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 */ + 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); + + 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"))); + + ret = execute_sp_cursoroption(cursor_handle, code, ivalue); + } + + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursoroption failed: %d", ret))); + break; + } + case PLTSQL_EXEC_SP_CURSORCLOSE: { - val = exec_eval_expr(estate, stmt->opt2, &isnull, &restype, &restypmod); + 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); + errmsg("cursor argument of sp_cursorfetch is null"))); + + ret = execute_sp_cursorclose(cursor_handle); - ret = execute_sp_cursoroption2(cursor_handle, code, cvalue); + if (ret > 0) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("sp_cursorclose failed: %d", ret))); + break; } - else + case PLTSQL_EXEC_SP_EXECUTESQL: { - ivalue = exec_eval_int(estate, stmt->opt2, &isnull); + 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("value argument of sp_cursoroption is null"))); + errmsg("batch string argument of sp_executesql is null"))); - ret = execute_sp_cursoroption(cursor_handle, code, ivalue); - } + batchstr = convert_value_to_string(estate, batch, restype); - 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"))); - - 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("batch string argument of sp_executesql is null"))); - - batchstr = convert_value_to_string(estate, batch, restype); - - args = create_args(0); - if (stmt->param_def) - { - Datum paramdef; - Oid restype; - int32 restypmod; - char *paramdefstr; - bool isnull; + args = create_args(0); + if (stmt->param_def) + { + 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); + /* + * 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"))); + if (isnull) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("NULL param definition"))); - paramdefstr = convert_value_to_string(estate, paramdef, restype); + paramdefstr = convert_value_to_string(estate, paramdef, restype); - if (strcmp(paramdefstr, "") != 0) /* check edge cases for sp_executesql */ - { - read_param_def(args, paramdefstr); + 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"))); + 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 +2276,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 +2301,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 +2337,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 +2345,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 +2361,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 +2376,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 +2392,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 +2413,7 @@ static char * next_word(char *dyntext) { StringInfoData ds; + initStringInfo(&ds); while (*dyntext && is_char_identpart(*dyntext)) @@ -2212,7 +2425,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 +2433,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 +2452,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 +2469,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 +2478,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 +2503,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 +2522,8 @@ read_param_def(InlineCodeBlockArgs *args, const char *paramdefstr) } } -InlineCodeBlockArgs *create_args(int numargs) +InlineCodeBlockArgs * +create_args(int numargs) { InlineCodeBlockArgs *args; @@ -2319,7 +2537,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 +2548,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 +2567,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 +2587,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 +2601,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 +2630,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 +2644,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 +2660,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 +2675,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 +2715,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 +2736,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 +2748,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 +2786,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 +2812,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 +2837,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 +2890,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 +2907,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 +2924,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,26 +2970,34 @@ 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; } +bool called_from_tsql_insert_exec() +{ + if (sql_dialect != SQL_DIALECT_TSQL) + return false; + return called_from_tsql_insert_execute; +} + /* * For naked SELECT stmt in INSERT ... EXECUTE, instead of pushing the result to * the client, we accumulate the result in estate->tuple_store (similar to @@ -2773,10 +3021,11 @@ exec_stmt_insert_execute_select(PLtsql_execstate *estate, PLtsql_expr *query) /* Use eval_mcontext for tuple conversion work */ oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate)); + called_from_tsql_insert_execute = true; tupmap = convert_tuples_by_position(portal->tupDesc, estate->tuple_store_desc, gettext_noop("structure of query does not match function result type")); - + called_from_tsql_insert_execute = false; while (true) { uint64 i; @@ -2794,7 +3043,11 @@ exec_stmt_insert_execute_select(PLtsql_execstate *estate, PLtsql_expr *query) HeapTuple tuple = SPI_tuptable->vals[i]; if (tupmap) + { + called_from_tsql_insert_execute = true; tuple = execute_attr_map_tuple(tuple, tupmap); + called_from_tsql_insert_execute = false; + } tuplestore_puttuple(estate->tuple_store, tuple); if (tupmap) heap_freetuple(tuple); @@ -2813,10 +3066,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 +3083,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); } } @@ -2878,16 +3137,378 @@ int exec_stmt_insert_bulk(PLtsql_execstate *estate, PLtsql_stmt_insert_bulk *stm return PLTSQL_RC_OK; } +int exec_stmt_dbcc(PLtsql_execstate *estate, PLtsql_stmt_dbcc *stmt) +{ + switch (stmt->dbcc_stmt_type) + { + case PLTSQL_DBCC_CHECKIDENT: + exec_stmt_dbcc_checkident(stmt); + break; + default: + Assert(0); + } + return PLTSQL_RC_OK; +} + +void exec_stmt_dbcc_checkident(PLtsql_stmt_dbcc *stmt) +{ + struct dbcc_checkident dbcc_stmt = stmt->dbcc_stmt_data.dbcc_checkident; + Relation rel; + TupleDesc tupdesc; + char *db_name = NULL; + char *max_identity_value_str = NULL; + char *query = NULL; + char *attname; + char *token; + const char *schema_name; + const char *nsp_name; + const char *user; + const char *guest_role_name; + const char *dbo_role_name; + const char *login; + int64 max_identity_value = 0; + int64 cur_identity_value = 0; + int attnum; + int rc = 0; + int64 reseed_value = 0; + Oid nsp_oid; + Oid table_oid; + Oid seqid = InvalidOid; + Oid current_user_id = GetUserId(); + volatile bool cur_value_is_null = true; + bool login_is_db_owner; + StringInfoData msg; + bool is_float_value; + bool is_cross_db = false; + + + if(dbcc_stmt.new_reseed_value) + { + /* If float value is passed as reseed_value, only part before decimal is considered */ + is_float_value = strchr(dbcc_stmt.new_reseed_value, '.') != NULL; + + if (is_float_value) + { + if (dbcc_stmt.new_reseed_value[0] == '.' || + (dbcc_stmt.new_reseed_value[0] == '-' && dbcc_stmt.new_reseed_value[1] == '.')) + reseed_value = 0; + else + { + token = strtok(dbcc_stmt.new_reseed_value, "."); + reseed_value = pg_strtoint64(token); + pfree(token); + } + } + else + reseed_value = pg_strtoint64(dbcc_stmt.new_reseed_value); + } + + db_name = get_cur_db_name(); + if (dbcc_stmt.db_name) + { + if (!DbidIsValid(get_db_id(dbcc_stmt.db_name))) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("database \"%s\" does not exist", dbcc_stmt.db_name))); + } + if (pg_strncasecmp(db_name, dbcc_stmt.db_name, NAMEDATALEN) != 0) + { + is_cross_db = true; + pfree(db_name); + db_name = pstrdup(dbcc_stmt.db_name); + } + } + + user = get_user_for_database(db_name); + login_is_db_owner = 0 == strncmp(GetUserNameFromId(GetSessionUserId(), false), + get_owner_of_db(db_name), NAMEDATALEN); + + /* Raise an error if the login does not have access to the database */ + if(is_cross_db) + { + if (user) + SetCurrentRoleId(GetSessionUserId(), false); + else + { + login = GetUserNameFromId(GetSessionUserId(), false); + pfree(db_name); + 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, dbcc_stmt.db_name))); + } + } + + /* get physical schema name from logical schema name */ + if (dbcc_stmt.schema_name) + { + schema_name = dbcc_stmt.schema_name; + nsp_name = get_physical_schema_name(db_name, dbcc_stmt.schema_name); + } + else + { + /* + * If schema_name is not provided, find default schema for current user + * and get physical schema name + */ + guest_role_name = get_guest_role_name(db_name); + dbo_role_name = get_dbo_role_name(db_name); + + /* user will never be null here as cross-db calls are already handled */ + Assert(user != NULL); + + schema_name = get_authid_user_ext_schema_name((const char *) db_name, user); + if ((dbo_role_name && strcmp(user, dbo_role_name) == 0)) + { + nsp_name = get_dbo_schema_name(db_name); + } + else if ((guest_role_name && strcmp(user, guest_role_name) == 0)) + { + nsp_name = get_guest_schema_name(db_name); + } + else + { + nsp_name = get_physical_schema_name(db_name, schema_name); + } + } + pfree(db_name); + + /* + * get schema oid from physical schema name, it will return InvalidOid if + * user don't have lookup access + */ + nsp_oid = get_namespace_oid(nsp_name, false); + + if(!OidIsValid(nsp_oid)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", schema_name))); + } + + /* Permission check */ + if (!(pg_namespace_ownercheck(nsp_oid, GetUserId()) || + has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false)) || + login_is_db_owner)) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, nsp_name); + + table_oid = get_relname_relid(dbcc_stmt.table_name, nsp_oid); + if(!OidIsValid(table_oid)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", dbcc_stmt.table_name))); + } + + rel = RelationIdGetRelation(table_oid); + tupdesc = RelationGetDescr(rel); + + /* Find Identity column in table and associated sequence */ + for (attnum = 0; attnum < tupdesc->natts; attnum++) + { + Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum); + + if (attr->attidentity) + { + attname = NameStr(attr->attname); + seqid = getIdentitySequence(table_oid, attnum + 1, false); + break; + } + } + + RelationClose(rel); + + if (!OidIsValid(seqid)) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("'%s.%s' does not contain an identity column.", + nsp_name, dbcc_stmt.table_name))); + } + + PG_TRY(); + { + cur_identity_value = DirectFunctionCall1(pg_sequence_last_value, + ObjectIdGetDatum(seqid)); + cur_value_is_null = false; + } + PG_CATCH(); + { + FlushErrorState(); + } + PG_END_TRY(); + + if (!dbcc_stmt.no_infomsgs) + initStringInfo(&msg); + + PG_TRY(); + { + /* + * Acquiring an AccessExclusiveLock on the table is essential when + * reseeding the identity current value to new_ressed_value to + * ensure concurrency control. + */ + if(dbcc_stmt.new_reseed_value) + { + LockRelationOid(table_oid, AccessExclusiveLock); + } + else + { + LockRelationOid(table_oid, ShareLock); + } + + /* + * If cur_value_is_null is true, then the function pg_sequence_last_value + * has returned a NULL value, which means either no rows have been + * inserted into the table yet, or TRUNCATE TABLE command has been used + * to delete all rows. In this case, after DBCC CHECKIDENT the next + * row inserted will have new_reseed_value as the identity value. + */ + if (cur_value_is_null) + { + if (dbcc_stmt.new_reseed_value) + { + if (!dbcc_stmt.no_infomsgs) + appendStringInfo(&msg, "Checking identity information: current identity value 'NULL'.\n"); + DirectFunctionCall3(setval3_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(reseed_value), + BoolGetDatum(false)); + } + else + { + if (!dbcc_stmt.no_infomsgs) + appendStringInfo(&msg, "Checking identity information: current identity value 'NULL', current column value 'NULL'.\n"); + } + } + + else + { + if (dbcc_stmt.new_reseed_value) + { + /* + * Print informational messages if NO_INFOMSGS is not passed as a + * DBCC command option. + */ + if (!dbcc_stmt.no_infomsgs) + appendStringInfo(&msg, "Checking identity information: current identity value '%ld'.\n", cur_identity_value); + + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(reseed_value)); + } + else + { + SPI_connect(); + query = psprintf("SELECT MAX(%s) FROM %s.%s", attname, + schema_name, dbcc_stmt.table_name); + rc = SPI_execute(query, true, 0); + + if (rc != SPI_OK_SELECT) + elog(ERROR, "SPI_execute failed: %s", SPI_result_code_string(rc)); + + max_identity_value_str = SPI_getvalue(SPI_tuptable->vals[0], + SPI_tuptable->tupdesc, 1); + + SPI_freetuptable(SPI_tuptable); + + if(max_identity_value_str) + max_identity_value = pg_strtoint64(max_identity_value_str); + + if (!dbcc_stmt.no_infomsgs) + { + appendStringInfo(&msg, "Checking identity information: current identity value '%ld', current column value '%s'.\n", + cur_identity_value, + max_identity_value_str ? max_identity_value_str : "NULL"); + } + + /* + * RESEED option only resets the identity column value if the + * current identity value for a table is less than the maximum + * identity value stored in the identity column. + */ + if (dbcc_stmt.is_reseed && max_identity_value_str && + cur_identity_value < max_identity_value) + { + DirectFunctionCall2(setval_oid, + ObjectIdGetDatum(seqid), + Int64GetDatum(max_identity_value)); + } + } + } + + if (is_cross_db) + SetCurrentRoleId(current_user_id, false); + } + PG_CATCH(); + { + if (is_cross_db) + SetCurrentRoleId(current_user_id, false); + + if(query) + pfree(query); + if (max_identity_value_str) + pfree(max_identity_value_str); + + if(rc != 0) + { + SPI_finish(); + /* running 'SELECT MAX' query above holds a AccessShareLock on table, we want to unlock that as well */ + UnlockRelationOid(table_oid, AccessShareLock); + } + if(!dbcc_stmt.new_reseed_value) + { + UnlockRelationOid(table_oid, ShareLock); + } + if(msg.data) + { + pfree(msg.data); + } + + PG_RE_THROW(); + } + PG_END_TRY(); + + if(query) + pfree(query); + if (max_identity_value_str) + pfree(max_identity_value_str); + if(rc != 0) + { + SPI_finish(); + /* running 'SELECT MAX' query above holds a AccessShareLock on table, we want to unlock that as well */ + UnlockRelationOid(table_oid, AccessShareLock); + } + + if(!dbcc_stmt.new_reseed_value) + { + UnlockRelationOid(table_oid, ShareLock); + } + + if (!dbcc_stmt.no_infomsgs) + { + appendStringInfo(&msg, "DBCC execution completed. If DBCC printed error messages, contact your system administrator."); + /* send message to user */ + if (*pltsql_protocol_plugin_ptr && (*pltsql_protocol_plugin_ptr)->send_info) + ((*pltsql_protocol_plugin_ptr)->send_info) (0, 1, 0, msg.data, 0); + pfree(msg.data); + } + +} + + 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 +3540,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 +3555,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 +3593,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 +3604,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 +3617,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 +3642,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 +3656,284 @@ 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; } + +static int +exec_stmt_grantschema(PLtsql_execstate *estate, PLtsql_stmt_grantschema *stmt) +{ + List *parsetree_list; + ListCell *parsetree_item; + char *dbname = get_cur_db_name(); + char *login = GetUserNameFromId(GetSessionUserId(), false); + bool login_is_db_owner; + Oid datdba; + char *rolname; + char *schema_name; + ListCell *lc; + ListCell *lc1; + Oid schemaOid; + + /* + * If the login is not the db owner or the login is not the member of + * sysadmin or login is not the schema owner, then it doesn't have the permission to GRANT/REVOKE. + */ + login_is_db_owner = 0 == strncmp(login, get_owner_of_db(dbname), NAMEDATALEN); + datdba = get_role_oid("sysadmin", false); + schema_name = get_physical_schema_name(dbname, stmt->schema_name); + schemaOid = LookupExplicitNamespace(schema_name, true); + + if (!OidIsValid(schemaOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + schema_name))); + + if (!is_member_of_role(GetSessionUserId(), datdba) && !login_is_db_owner && !pg_namespace_ownercheck(schemaOid, GetUserId())) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot find the schema \"%s\", because it does not exist or you do not have permission.", stmt->schema_name))); + + foreach(lc1, stmt->privileges) + { + char *priv_name = (char *) lfirst(lc1); + foreach(lc, stmt->grantees) + { + char *grantee_name = (char *) lfirst(lc); + Oid role_oid; + bool grantee_is_db_owner; + rolname = get_physical_user_name(dbname, grantee_name); + role_oid = get_role_oid(rolname, true); + grantee_is_db_owner = 0 == strncmp(grantee_name, get_owner_of_db(dbname), NAMEDATALEN); + + + if (role_oid == InvalidOid) + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot find the principal '%s', because it does not exist or you do not have permission.", grantee_name))); + + if (pg_namespace_ownercheck(schemaOid, role_oid) || is_member_of_role(role_oid, datdba) || grantee_is_db_owner) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself."))); + + parsetree_list = gen_grantschema_subcmds(schema_name, rolname, stmt->is_grant, stmt->with_grant_option, priv_name); + /* Run all subcommands */ + foreach(parsetree_item, parsetree_list) + { + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + PlannedStmt *wrapper; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = 0; + + /* do this step */ + ProcessUtility(wrapper, + "(GRANT SCHEMA )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + } + /* Add entry for each grant statement. */ + if (stmt->is_grant && !check_bbf_schema_for_entry(stmt->schema_name, "ALL", priv_name, rolname)) + add_entry_to_bbf_schema(stmt->schema_name, "ALL", priv_name, rolname, NULL); + /* Remove entry for each revoke statement. */ + if (!stmt->is_grant && check_bbf_schema_for_entry(stmt->schema_name, "ALL", priv_name, rolname)) + { + /* If any object in the schema has the OBJECT level permission. Then, internally grant that permission back. */ + grant_perms_to_objects_in_schema(stmt->schema_name, priv_name, rolname); + del_from_bbf_schema(stmt->schema_name, "ALL", priv_name, rolname); + } + } + } + return PLTSQL_RC_OK; +} + +/* + * ALTER AUTHORIZATION ON DATABASE::dbname TO loginname + */ +static int +exec_stmt_change_dbowner(PLtsql_execstate *estate, PLtsql_stmt_change_dbowner *stmt) +{ + char *new_owner_is_user; + + /* Verify target database exists. */ + if (!DbidIsValid(get_db_id(stmt->db_name))) + { + ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), + errmsg("Cannot find the database '%s', because it does not exist or you do not have permission.", stmt->db_name))); + } + + /* Verify new owner exists as a login. */ + if (get_role_oid(stmt->new_owner_name, true) == InvalidOid) + { + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot find the principal '%s', because it does not exist or you do not have permission.", stmt->new_owner_name))); + } + + /* T-SQL allows granting ownership to yourself when you are owner already, even without having sysadmin role. */ + if (get_role_oid(stmt->new_owner_name, true) == GetSessionUserId()) // Granting ownership to myself? + { + /* Is the current login already DB owner? */ + if (get_role_oid(get_owner_of_db(stmt->db_name), true) == GetSessionUserId()) + { + /* Current login is DB owner, so perform the update */ + update_db_owner(stmt->new_owner_name, stmt->db_name); + return PLTSQL_RC_OK; + } + } + + /* + * The executing login must have sysadmin role: even when the current session is the owner, but has no sysadmin role, + * T-SQL does not allow the owner to grant ownership to another login -- not even to 'sa'. + */ + if (!has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))) + { + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot find the principal '%s', because it does not exist or you do not have permission.", stmt->new_owner_name))); + } + + /* The new owner cannot be a user in the database already (but 'guest' user is fine). */ + new_owner_is_user = get_authid_user_ext_physical_name(stmt->db_name, stmt->new_owner_name); + if (!new_owner_is_user) + { + // OK to proceed + } + else if (new_owner_is_user && pg_strcasecmp(new_owner_is_user, "guest") == 0) + { + // OK to proceed + } + else + { + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("The proposed new database owner is already a user or aliased in the database."))); + } + + /* All validations done, perform the actual update */ + update_db_owner(stmt->new_owner_name, stmt->db_name); + return PLTSQL_RC_OK; +} + +static int +exec_stmt_fulltextindex(PLtsql_execstate *estate, PLtsql_stmt_fulltextindex *stmt) +{ + char *table_name; + char *ft_index_name; + char *query_str; + char *old_ft_index_name; // existing fulltext index name + char *uniq_index_name; + const char *schema_name; + Oid schemaOid; + Oid relid; + List *column_name; + char *dbname = get_cur_db_name(); + char *login = GetUserNameFromId(GetSessionUserId(), false); + Oid datdba; + bool login_is_db_owner; + bool is_create; + + Assert(stmt->schema_name != NULL); + + /* + * If the login is not the db owner or the login is not the member of + * sysadmin or login is not the schema owner, then it doesn't have the permission to CREATE/DROP FULLTEXT INDEX. + */ + login_is_db_owner = 0 == strncmp(login, get_owner_of_db(dbname), NAMEDATALEN); + datdba = get_role_oid("sysadmin", false); + schema_name = gen_schema_name_for_fulltext_index((char *)stmt->schema_name); + schemaOid = LookupExplicitNamespace(schema_name, true); + table_name = stmt->table_name; + is_create = stmt->is_create; + + // Check if schema exists + if (!OidIsValid(schemaOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + stmt->schema_name))); + + // Check if the user has necessary permissions for CREATE/DROP FULLTEXT INDEX + if (!is_member_of_role(GetSessionUserId(), datdba) && !login_is_db_owner && !pg_namespace_ownercheck(schemaOid, GetUserId())) + { + const char *error_msg = is_create ? "A default full-text catalog does not exist in the database or user does not have permission to perform this action" : "Cannot drop the full-text index, because it does not exist or you do not have permission"; + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("%s", error_msg))); + } + + relid = get_relname_relid((const char *) table_name, schemaOid); + + // Check if table exists + if (!OidIsValid(relid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", + table_name))); + + // Get the existing fulltext index name + old_ft_index_name = get_fulltext_index_name(relid, table_name); + + if (is_create) + { + uniq_index_name = construct_unique_index_name((char *) stmt->index_name, table_name); + if(is_unique_index(relid, (const char *) uniq_index_name)) + { + column_name = stmt->column_name; + ft_index_name = construct_unique_index_name("ft_index", table_name); + if (old_ft_index_name) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("A full-text index for table or indexed view \"%s\" has already been created.", + table_name))); + else + query_str = gen_createfulltextindex_cmds(table_name, schema_name, column_name, ft_index_name); + } + else + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("'\"%s\"' is not a valid index to enforce a full-text search key. A full-text search key must be a unique, non-nullable, single-column index which is not offline, is not defined on a non-deterministic or imprecise nonpersisted computed column, does not have a filter, and has maximum size of 900 bytes. Choose another index for the full-text key.", + stmt->index_name))); + } + else + { + if (old_ft_index_name) + query_str = gen_dropfulltextindex_cmds(old_ft_index_name, schema_name); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("Table or indexed view \"%s\" does not have a full-text index or user does not have permission to perform this action.", + table_name))); + } + + /* The above query will be + * executed using ProcessUtility() + */ + exec_utility_cmd_helper(query_str); + return PLTSQL_RC_OK; +} \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/pl_exec.c b/contrib/babelfishpg_tsql/src/pl_exec.c index 4a97dd7179..71f1deb51e 100644 --- a/contrib/babelfishpg_tsql/src/pl_exec.c +++ b/contrib/babelfishpg_tsql/src/pl_exec.c @@ -53,6 +53,7 @@ #include "utils/snapmgr.h" #include "utils/syscache.h" #include "utils/typcache.h" +#include "utils/formatting.h" #include "pltsql.h" #include "access/xact.h" @@ -64,11 +65,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 +170,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 +260,181 @@ 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); +Datum pltsql_exec_tsql_cast_value(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 +442,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 +466,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 +479,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 +503,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 +514,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 +638,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,223 +648,233 @@ 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"))); - } + estate.err_stmt = (PLtsql_stmt *) (func->action); - /* - * 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"); + 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; - fcinfo->isnull = estate.retisnull; + rc = exec_stmt_iterative(&estate, func->exec_codes, &config); - if (estate.retisset || estate.insert_exec) - { - ReturnSetInfo *rsi = estate.rsi; - - /* 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"))); + } + + /* + * 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 we produced any tuples, send back the result */ - if (estate.tuple_store) + if (estate.retisset || estate.insert_exec) { - MemoryContext oldcxt; + ReturnSetInfo *rsi = estate.rsi; - rsi->setResult = estate.tuple_store; - oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt); - rsi->setDesc = CreateTupleDescCopy(estate.tuple_store_desc); - MemoryContextSwitchTo(oldcxt); + /* 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); + } + 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); + /* Drop the tables linked to table variables */ + pltsql_clean_table_variables(&estate, func); + /* Clean up any leftover temporary memory */ pltsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); @@ -879,12 +893,12 @@ pltsql_exec_function(PLtsql_function *func, FunctionCallInfo fcinfo, if (*pltsql_plugin_ptr && (*pltsql_plugin_ptr)->func_end) ((*pltsql_plugin_ptr)->func_end) (&estate, func); - /* Drop the tables linked to table variables */ - pltsql_clean_table_variables(&estate, func); - /* Close/Deallocate LOCAL cursors */ pltsql_cleanup_local_cursors(&estate); + /* Drop the tables linked to table variables */ + pltsql_clean_table_variables(&estate, func); + /* Clean up any leftover temporary memory */ pltsql_destroy_econtext(&estate); exec_eval_cleanup(&estate); @@ -1023,7 +1037,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; @@ -1033,6 +1047,14 @@ pltsql_exec_trigger(PLtsql_function *func, *rec_old; HeapTuple rettup; + /* Check if this trigger is called as part of any of postgres' function, procedure or trigger. */ + if (!pltsql_support_tsql_transactions()) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger."))); + } + /* * Setup the execution state */ @@ -1115,7 +1137,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 +1148,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)) + { + /* 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 */ + } - if (retdesc != RelationGetDescr(trigdata->tg_relation)) + /* + * 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 +1274,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 +1368,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 +1500,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 +1581,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 +1928,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 +2193,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 +2265,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 +2745,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 +2786,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 +3154,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 +3297,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 +3427,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 +3452,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 +3489,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 +3569,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 +3593,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 +3910,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 +4219,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 +4245,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,8 +4349,10 @@ 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->pivot_number = 0; + estate->pivot_parsetree_list = NIL; + estate->explain_infos = NIL; /* @@ -4328,10 +4361,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 +4456,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 +4476,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 +4494,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 +4507,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 +4516,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 +4525,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 +4533,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 +4557,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 +4621,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 +4680,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; - - - /* - * 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; - } + /* + * Set up ParamListInfo to pass to executor + */ + paramLI = setup_param_list(estate, expr); - /* - * 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; - if (!stmt->is_tsql_select_assign_stmt) - { - /* set the target to NULL(s) */ - exec_move_row(estate, target, NULL, tuptab->tupdesc); - } - else + 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 (enable_txn_in_triggers) + { + if (!stmt->need_to_push_result) + /* before trigger execution, set the rowcount */ { - /* A SELECT statement that returns zero rows will leave the target(s) unchanged */ + exec_set_rowcount(SPI_processed); } + /* Close nesting level on engine side */ + EndCompositeTriggers(false); + estate->tsql_trigger_flags &= ~TSQL_TRIGGER_STARTED; } - else + + if (columns_updated_list != NIL && 0 == pltsql_trigger_depth) { - /* 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))) + ListCell *lc; + + foreach(lc, columns_updated_list) { - char *errdetail; + List *list = (List *) lfirst(lc); - if (estate->func->print_strict_params) - errdetail = format_expr_params(estate, expr); - else - errdetail = NULL; + if (list != NIL) + list_free_deep(list); + } + list_free(columns_updated_list); + columns_updated_list = NIL; + } + + 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); + } + + /* 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 +5100,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 +5118,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 +5189,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 +5209,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 +5288,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 +5401,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 +5414,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 +5465,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 +5497,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 +5512,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 +5527,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 +5542,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 +5571,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 +5589,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 +5601,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 +5660,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 +5711,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 +5986,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 +6027,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 +6104,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 +6124,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 +6203,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 +6273,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 +6306,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 +6328,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 +6337,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); @@ -6320,6 +6413,30 @@ exec_assign_value(PLtsql_execstate *estate, var->datatype->typoid, var->datatype->atttypmod); + /* Special handling when target variable is babelfish GUC */ + if(var->is_babelfish_guc) + { + StringInfo buf; + if (isNull) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("Invalid argument for SET %s. Must be a non-null value.", + asc_toupper(var->refname, strlen(var->refname))))); + + buf = makeStringInfo(); + if(var->datatype->typoid == INT4OID) + appendStringInfo(buf, "%d", DatumGetInt32(newvalue)); + else + appendStringInfoString(buf, TextDatumGetCString(newvalue)); + + set_config_option(psprintf("babelfishpg_tsql.%s", var->refname), buf->data, + PGC_USERSET, PGC_S_SESSION, GUC_ACTION_SET, + true, 0, false); + pfree(buf->data); + pfree(buf); + break; + } + if (isNull && var->notnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), @@ -6856,10 +6973,11 @@ 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); - *isnull = false; + *isnull = !tbl->tblname ? true : false; break; } @@ -6877,7 +6995,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 +7080,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 +7238,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 +7332,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 +7576,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 +7590,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 +7642,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 +7663,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 +7789,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 +7922,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 +7997,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 +8029,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 +8066,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 +8138,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 +8178,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 +8669,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 +9103,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 +9190,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 +9205,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 +9312,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 +9458,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 +9471,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 +9545,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 +9565,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 +9584,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 +9594,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 +9650,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 +9671,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 +9724,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 +9741,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 +9828,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 +10128,25 @@ 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; + bool old_abort_curr_txn = AbortCurTransaction; PG_TRY(); { - foreach (lc, func->table_varnos) + /* + * Temporarily set this to false to allow DROP to continue. + * Othewise, DROP would not be allowed to acquire xlock on the + * relation. + */ + AbortCurTransaction = false; + + foreach(lc, func->table_varnos) { n = lfirst_int(lc); if (estate->datums[n]->dtype != PLTSQL_DTYPE_TBL) @@ -10019,14 +10154,16 @@ pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_function *func) tbl = (PLtsql_tbl *) estate->datums[n]; if (!tbl->need_drop) 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) { @@ -10035,16 +10172,23 @@ pltsql_clean_table_variables(PLtsql_execstate *estate, PLtsql_function *func) append_explain_info(NULL, query); } } + + Assert(!AbortCurTransaction); /* engine should not change this value */ + AbortCurTransaction = old_abort_curr_txn; } PG_CATCH(); { - pltsql_explain_only = old_pltsql_explain_only; /* Recover EXPLAIN ONLY mode */ + Assert(!AbortCurTransaction); /* engine should not change this value */ + AbortCurTransaction = old_abort_curr_txn; + + 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 +10211,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 +10225,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 +10258,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 +10282,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 +10306,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 +10331,49 @@ 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. - */ - 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)) + + if (stmt->is_create_view && stmt->schema_name != NULL && (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; @@ -10228,3 +10387,13 @@ get_original_query_string(void) { return original_query_string; } + +Datum pltsql_exec_tsql_cast_value(Datum value, bool *isnull, + Oid valtype, int32 valtypmod, + Oid reqtype, int32 reqtypmod) +{ + return exec_cast_value(get_current_tsql_estate(), + value, isnull, + valtype, valtypmod, + reqtype, reqtypmod); +} 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 0ee473f33e..6ec9d93652 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)) - { - char *prefix = "instr_tsql_"; - char *funcname_edited = replace_with_underscore(funcName); - StringInfoData metricName; - initStringInfo(&metricName); - - appendStringInfoString(&metricName, prefix); - appendStringInfoString(&metricName, funcname_edited); - - if (!(*pltsql_instr_plugin_ptr)->pltsql_instr_increment_func_metric(metricName.data)) - { - /* check with "unsupported" in prefix */ - prefix = "instr_unsupported_tsql_"; - - resetStringInfo(&metricName); - appendStringInfoString(&metricName, prefix); - appendStringInfoString(&metricName, funcname_edited); - (*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); - } -} 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)); @@ -361,8 +338,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; @@ -383,148 +360,167 @@ 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_KILL: + { + /* Nothing to free */ + 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_INIT: + { + PLtsql_stmt_init *init = (PLtsql_stmt_init *) stmt; + ListCell *l; - free_expr(select->sqlstmt); + foreach(l, init->inits) + free_stmt((PLtsql_stmt *) lfirst(l)); + break; + } - break; - } + case PLTSQL_STMT_QUERY_SET: + { + PLtsql_stmt_query_set *select = (PLtsql_stmt_query_set *) stmt; - 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; - } + free_expr(select->sqlstmt); - case PLTSQL_STMT_PUSH_RESULT: - { - PLtsql_stmt_push_result *push = (PLtsql_stmt_push_result *) stmt; - free_expr(push->query); - break; - } + break; + } - case PLTSQL_STMT_EXEC: - { - PLtsql_stmt_exec *exec = (PLtsql_stmt_exec *) stmt; - free_expr(exec->expr); - 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_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_CHANGE_DBOWNER: + case PLTSQL_STMT_GRANTSCHEMA: + case PLTSQL_STMT_FULLTEXTINDEX: 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)); + 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; + } + case PLTSQL_STMT_DBCC: + { + /* Nothing to free */ break; } - case PLTSQL_STMT_SAVE_CTX: - case PLTSQL_STMT_RESTORE_CTX_FULL: - case PLTSQL_STMT_RESTORE_CTX_PARTIAL: - { - break; - } - default: + default: elog(ERROR, "unrecognized cmd_type: %d", stmt->cmd_type); break; } @@ -534,85 +530,95 @@ 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_kill(PLtsql_stmt_kill *stmt_kill); +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_change_dbowner(PLtsql_stmt_change_dbowner *stmt_change_dbowner); +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_dbcc(PLtsql_stmt_dbcc *stmt_dbcc); 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_kill(PLtsql_stmt_kill *stmt_kill) +{ + printf("KILL %d\n", stmt_kill->spid); } 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) @@ -626,7 +632,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"); @@ -648,12 +654,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); @@ -662,39 +670,62 @@ 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); resetStringInfo(&grantees_names); } +void +dump_stmt_change_dbowner(PLtsql_stmt_change_dbowner *stmt_change_dbowner) +{ + printf("ALTER AUTHORIZATION ON DATABASE::%s TO %s\n", stmt_change_dbowner->db_name, stmt_change_dbowner->new_owner_name); +} + 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_dbcc(PLtsql_stmt_dbcc *stmt_dbcc) +{ + printf("DBCC "); + switch (stmt_dbcc->dbcc_stmt_type) + { + case PLTSQL_DBCC_CHECKIDENT: + printf("CHECKIDENT"); + break; + default: + elog(ERROR, "unrecognized dbcc statement type: %d", stmt_dbcc->dbcc_stmt_type); + break; + } + printf(" STATEMENT\n"); } 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 @@ -719,95 +750,110 @@ 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_KILL: + { + dump_stmt_kill((PLtsql_stmt_kill *) 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_CHANGE_DBOWNER: + { + dump_stmt_change_dbowner((PLtsql_stmt_change_dbowner *) stmt); + break; + } + case PLTSQL_STMT_INSERT_BULK: + { + dump_stmt_insert_bulk((PLtsql_stmt_insert_bulk *) stmt); + break; + } + case PLTSQL_STMT_DBCC: + { + dump_stmt_dbcc((PLtsql_stmt_dbcc *) 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..bddd8e6ab7 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,33 @@ 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: + case PLTSQL_STMT_CHANGE_DBOWNER: + return "ALTER AUTHORIZATION ON DATABASE::"; + /* 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"; + case PLTSQL_STMT_DBCC: + return "DBCC"; + default: return "Add try catch"; } @@ -436,7 +440,7 @@ free_stmt(PLtsql_stmt *stmt) { if (stmt == NULL) return; - + switch (stmt->cmd_type) { case PLTSQL_STMT_BLOCK: @@ -577,8 +581,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 @@ -798,6 +802,7 @@ void pltsql_free_function_memory(PLtsql_function *func) { int i; + MemoryContext func_cxt = NULL; /* Better not call this on an in-use function */ Assert(func->use_count == 0); @@ -841,16 +846,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) @@ -861,10 +867,16 @@ pltsql_free_function_memory(PLtsql_function *func) * And finally, release all memory except the PLtsql_function struct * itself (which has to be kept around because there may be multiple * fn_extra pointers to it). + * It is also possible that PLtsql_function struct was allocated in + * the same func->fn_cxt memory context, so we avoid accessing struct + * fields after memory context is released. */ if (func->fn_cxt) - MemoryContextDelete(func->fn_cxt); - func->fn_cxt = NULL; + { + func_cxt = func->fn_cxt; + func->fn_cxt = NULL; + MemoryContextDelete(func_cxt); + } } @@ -1010,7 +1022,7 @@ dump_stmt(PLtsql_stmt *stmt) dump_set((PLtsql_stmt_set *) stmt); break; default: - dump_stmt2(stmt); + dump_stmt2(stmt); break; } } @@ -1800,7 +1812,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 d8eccb3337..10297b0c90 100644 --- a/contrib/babelfishpg_tsql/src/pl_handler.c +++ b/contrib/babelfishpg_tsql/src/pl_handler.c @@ -16,7 +16,9 @@ #include "postgres.h" #include "access/attnum.h" +#include "access/relation.h" #include "access/htup_details.h" +#include "access/parallel.h" #include "access/table.h" #include "catalog/heap.h" #include "catalog/indexing.h" @@ -26,10 +28,12 @@ #include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "commands/createas.h" #include "commands/dbcommands.h" #include "commands/defrem.h" #include "commands/sequence.h" #include "commands/tablecmds.h" +#include "commands/trigger.h" #include "commands/user.h" #include "common/md5.h" #include "common/string.h" @@ -47,7 +51,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" @@ -71,6 +75,7 @@ #include "collation.h" #include "dbcmds.h" #include "err_handler.h" +#include "extendedproperty.h" #include "guc.h" #include "hooks.h" #include "iterative_exec.h" @@ -80,10 +85,12 @@ #include "session.h" #include "pltsql.h" #include "pl_explain.h" +#include "table_variable_mvcc.h" #include "access/xact.h" extern bool escape_hatch_unique_constraint; +extern int escape_hatch_set_transaction_isolation_level; extern bool pltsql_recursive_triggers; extern bool restore_tsql_tabletype; extern bool babelfish_dump_restore; @@ -92,6 +99,7 @@ extern bool pltsql_nocount; extern List *babelfishpg_tsql_raw_parser(const char *str, RawParseMode mode); extern bool install_backend_gram_hooks(); +static bool check_identity_insert(char **newal, void **extra, GucSource source); static void assign_identity_insert(const char *newval, void *extra); static void assign_textsize(int newval, void *extra); extern Datum init_collid_trans_tab(PG_FUNCTION_ARGS); @@ -102,43 +110,47 @@ 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 has_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; +static List *transformSelectIntoStmt(CreateTableAsStmt *stmt); +static char *get_oid_type_string(int type_oid); +static int64 get_identity_into_args(Node *node); +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 +160,33 @@ 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); + +static void bbf_ExecDropStmt(DropStmt *stmt); + +static int isolation_to_int(char *isolation_level); +static void bbf_set_tran_isolation(char *new_isolation_level_str); + +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 +209,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}; @@ -255,211 +274,355 @@ set_procid(Oid oid) procid_var = oid; } +static bool +check_identity_insert(char** newval, void **extra, GucSource source) +{ + /* + * Workers synchronize the parameter at the beginning of each parallel + * operation. Avoid performing parameter assignment uring parallel operation. + */ + if (IsParallelWorker() && !InitializingParallelWorker) + { + /* + * A change other than during startup, for example due to a SET clause + * attached to a function definition, should be rejected, as there is + * nothing we can do inside the worker to make it take effect. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_TRANSACTION_STATE), + errmsg("cannot change identity_insert during a parallel operation"))); + } + + return true; +} + 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 (IsParallelWorker()) + return; + + 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); - /* Clean up */ - pfree(input_string); - list_free(elemlist); - } + 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"))); + } + + /* 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; + Oid relid; + ListCell *lc; + + if (!babelfish_dump_restore || IsBinaryUpgrade) + break; + + relid = RangeVarGetRelid(stmt->relation, NoLock, false); + + /* + * Insert new dbid and owner columns 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 = NULL; + A_Const *dbidValue = NULL; + A_Const *ownerValue = NULL; + bool dbid_found = false; + bool owner_found = false; + + /* Skip if dbid and owner column already exists */ + foreach(lc, stmt->cols) + { + ResTarget *col = (ResTarget *) lfirst(lc); + + if (pg_strcasecmp(col->name, "dbid") == 0) + dbid_found = true; + if (relid == sysdatabases_oid && + pg_strcasecmp(col->name, "owner") == 0) + owner_found = true; + } + if (dbid_found && (owner_found || relid != sysdatabases_oid)) + break; + + /* + * Populate dbid column in Babelfish catalog tables with + * new one. + */ + if (!dbid_found) + { + /* const value node to store into values clause */ + dbidValue = makeNode(A_Const); + dbidValue->val.ival.type = T_Integer; + dbidValue->val.ival.ival = getDbidForLogicalDbRestore(relid); + dbidValue->location = -1; + + /* dbid column to store into InsertStmt's target list */ + col = makeNode(ResTarget); + col->name = "dbid"; + col->name_location = -1; + col->indirection = NIL; + col->val = NULL; + col->location = -1; + stmt->cols = lappend(stmt->cols, col); + } + + /* + * Populate owner column in babelfish_sysdatabases catalog table with + * SA of the current database. + */ + if (!owner_found && relid == sysdatabases_oid) + { + /* const value node to store into values clause */ + ownerValue = makeNode(A_Const); + ownerValue->val.sval.type = T_String; + ownerValue->val.sval.sval = GetUserNameFromId(get_sa_role_oid(), false); + ownerValue->location = -1; + + /* owner column to store into InsertStmt's target list */ + col = makeNode(ResTarget); + col->name = "owner"; + col->name_location = -1; + col->indirection = NIL; + col->val = NULL; + col->location = -1; + stmt->cols = lappend(stmt->cols, col); + } + + foreach(lc, selectStmt->valuesLists) + { + List *sublist = (List *) lfirst(lc); + + if (!dbid_found) + sublist = lappend(sublist, dbidValue); + if (!owner_found && relid == sysdatabases_oid) + sublist = lappend(sublist, ownerValue); + } + } + break; + } + default: + break; + } 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. */ @@ -472,247 +635,258 @@ 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); } } } + if (parseTree->stmt->type == T_AlterTableStmt) + { + AlterTableStmt *atstmt = (AlterTableStmt *) parseTree->stmt; + ListCell *lc; + char *trig_schema; + char *rel_schema; + + foreach(lc, atstmt->cmds) + { + AlterTableCmd *cmd = (AlterTableCmd *)lfirst(lc); + if (cmd->subtype == AT_EnableTrig || cmd->subtype == AT_DisableTrig) + { + if (atstmt->objtype == OBJECT_TRIGGER) + { + trig_schema = cmd->schemaname; + } + else + { + trig_schema = NULL; + } + + if (atstmt->relation->schemaname != NULL) + { + rel_schema = atstmt->relation->schemaname; + } + else + { + rel_schema = get_authid_user_ext_schema_name(get_cur_db_name(), GetUserNameFromId(GetUserId(), false)); + } + + if (trig_schema != NULL && strcmp(trig_schema, rel_schema) != 0) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Trigger %s.%s on table %s.%s does not exists or table %s.%s does not exists", + trig_schema, cmd->name, rel_schema, atstmt->relation->relname, rel_schema, atstmt->relation->relname))); + } + + if(atstmt->relation->schemaname == NULL && rel_schema) + { + pfree((char *) rel_schema); + } + } + } + } + if (enable_schema_mapping()) rewrite_object_refs(parseTree->stmt); 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; } } -/* 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) +static void +pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) { - 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; + if (prev_post_parse_analyze_hook) + prev_post_parse_analyze_hook(pstate, query, jstate); - rte = (RangeTblEntry *) node; - if (rte->rtekind == RTE_SUBQUERY && rte->subquery && rte->subquery->commandType == CMD_SELECT) - pltsql_set_nulls_first(rte->subquery); - } + if (query->commandType == CMD_UTILITY && nodeTag((Node *) (query->utilityStmt)) == T_CreateStmt) + set_current_query_is_create_tbl_check_constraint(query->utilityStmt); - if (!query->sortClause) + if (sql_dialect != SQL_DIALECT_TSQL) return; - - foreach(lc, query->sortClause) + if (query->commandType == CMD_INSERT) { - 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) -{ - if (prev_post_parse_analyze_hook) - prev_post_parse_analyze_hook(pstate, query, jstate); - - 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); @@ -723,8 +897,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), @@ -735,15 +909,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, @@ -767,7 +941,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 { @@ -779,7 +953,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)) { @@ -789,7 +963,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) { @@ -813,12 +987,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, @@ -830,14 +1004,55 @@ 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; + ListCell *lc; - if (rowversion_column_name) - validate_rowversion_table_constraint(c, rowversion_column_name); - } + c->conname = construct_unique_index_name(c->conname, stmt->relation->relname); + + if (escape_hatch_unique_constraint != EH_IGNORE && + c->contype == CONSTR_UNIQUE) + { + foreach(lc, (List *) c->keys) + { + char *colname = NULL; + int colname_len = 0; + + /* T-SQL Parser might have directly prepared IndexElem instead of String*/ + if (nodeTag(lfirst(lc)) == T_IndexElem) { + IndexElem *ie = (IndexElem *) lfirst(lc); + colname = ie->name; + colname_len = strlen(colname); + } else { + colname = strVal(lfirst(lc)); + colname_len = strlen(colname); + } + + foreach(elements, stmt->tableElts) + { + Node *element = lfirst(elements); + if (nodeTag(element) == T_ColumnDef) + { + ColumnDef* def = (ColumnDef *) element; + + if (strlen(def->colname) == colname_len && + strncmp(def->colname, colname, colname_len) == 0 && + has_nullable_constraint(def)) + { + 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; default: break; @@ -848,15 +1063,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); @@ -876,9 +1091,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); @@ -904,9 +1119,18 @@ pltsql_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) errmsg("Only one identity column is allowed in a table"))); seen_identity = true; } + if (escape_hatch_unique_constraint != EH_IGNORE && + has_unique_nullable_constraint(castNode(ColumnDef, cmd->def))) + { + 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 (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), @@ -917,88 +1141,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); @@ -1010,57 +1246,61 @@ 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; + + 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; @@ -1068,30 +1308,26 @@ 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."))); } } } - else if (query->commandType == CMD_SELECT) - { - pltsql_set_nulls_first(query); - } } /* @@ -1173,8 +1409,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); @@ -1184,7 +1420,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; @@ -1201,43 +1437,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; } } } @@ -1245,49 +1482,57 @@ 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)); + char *colname = NULL; bool found = false; + /* T-SQL Parser might have directly prepared IndexElem instead of String*/ + if (nodeTag(lfirst(lc)) == T_IndexElem) { + IndexElem *ie = (IndexElem *) lfirst(lc); + colname = ie->name; + } else { + colname = strVal(lfirst(lc)); + } + 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; @@ -1313,8 +1558,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); @@ -1333,11 +1578,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 */ @@ -1384,8 +1629,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) { @@ -1431,7 +1676,7 @@ has_unique_nullable_constraint(ColumnDef *column) is_unique = true; break; case CONSTR_NOTNULL: - is_notnull =true; + is_notnull = true; break; default: break; @@ -1441,30 +1686,71 @@ has_unique_nullable_constraint(ColumnDef *column) return is_unique & !is_notnull; } -static bool is_nullable_constraint(Constraint *cst, Oid rel_oid) +/* has_nullable_constraint + * Given a Column definition + * return true if column does not have any NOT NULL constraint else false + */ +static bool +has_nullable_constraint(ColumnDef *column) { - ListCell *lc; + ListCell *clist; bool is_notnull = false; + foreach(clist, column->constraints) + { + Constraint *constraint = lfirst_node(Constraint, clist); + + switch (constraint->contype) + { + case CONSTR_NOTNULL: + is_notnull = true; + break; + default: + break; + } + } + + return !is_notnull; +} + +/* is_nullable_constraint + * Given a Constraint + * return true if atleast one of the attribute in the constraint is nullable else false + */ +static bool +is_nullable_constraint(Constraint *cst, Oid rel_oid) +{ + ListCell *lc; + bool is_null = false; + /* Loop through the constraint keys */ foreach(lc, cst->keys) { - String *strval = (String *) lfirst(lc); - const char *col_name = NULL; + 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)) + if (!get_attnotnull(rel_oid, attnum)) { - /* found a NOT NULL attr, break and return */ - is_notnull = true; + /* found a NULL attr, break and return */ + is_null = true; break; } } - return !is_notnull; + return is_null; } /* @@ -1475,12 +1761,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)) { @@ -1488,6 +1774,7 @@ get_attnotnull(Oid relid, AttrNumber attnum) att_tup = (Form_pg_attribute) GETSTRUCT(tp); result = att_tup->attnotnull; + ReleaseSysCache(tp); return result; @@ -1496,54 +1783,58 @@ get_attnotnull(Oid relid, AttrNumber attnum) return false; } +/* is_nullable_index + * Given an Index Statement + * return true if atleast one of the attribute in the index is nullable else false + */ static bool is_nullable_index(IndexStmt *stmt) { - ListCell *lc; - bool is_notnull = false; + ListCell *lc; + bool is_null = 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)) + if (!get_attnotnull(rel_oid, attnum)) { - is_notnull = true; + is_null = true; break; } } - return !is_notnull; + return is_null; } 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); @@ -1565,11 +1856,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) { @@ -1577,7 +1868,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; @@ -1609,16 +1900,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 = NULL; + AclResult aclresult; + Oid base_type; + int list_len; + if (prev_pltsql_sequence_datatype_hook) prev_pltsql_sequence_datatype_hook(pstate, newtypid, @@ -1647,7 +1939,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); @@ -1655,7 +1947,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); @@ -1677,8 +1969,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) @@ -1718,21 +2010,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, @@ -1751,18 +2045,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(); @@ -1779,7 +2073,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) @@ -1788,9 +2082,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); } } @@ -1798,105 +2094,6 @@ bbf_table_var_lookup(const char *relname, Oid relnamespace) return relid; } -/* - * Transaction processing using tsql semantics - */ -static void -PLTsqlProcessTransaction(Node *parsetree, - ParamListInfo params, - QueryCompletion *qc) -{ - char *txnName = NULL; - TransactionStmt *stmt = (TransactionStmt *) parsetree; - if (params != NULL && params->numParams > 0 && !params->params[0].isnull) - { - Oid typOutput; - bool typIsVarlena; - FmgrInfo finfo; - - Assert(params->numParams == 1); - getTypeOutputInfo(params->params[0].ptype, &typOutput, &typIsVarlena); - fmgr_info(typOutput, &finfo); - txnName = OutputFunctionCall(&finfo, params->params[0].value); - } - else - txnName = stmt->savepoint_name; - - if (txnName != NULL && strlen(txnName) > TSQL_TXN_NAME_LIMIT / 2) - ereport(ERROR, - (errcode(ERRCODE_NAME_TOO_LONG), - errmsg("Transaction name length %zu above limit %u", - strlen(txnName), TSQL_TXN_NAME_LIMIT / 2))); - - if (AbortCurTransaction) - { - if (stmt->kind == TRANS_STMT_BEGIN || - stmt->kind == TRANS_STMT_COMMIT || - stmt->kind == TRANS_STMT_SAVEPOINT) - 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."))); - } - - switch (stmt->kind) - { - case TRANS_STMT_BEGIN: - { - PLTsqlStartTransaction(txnName); - } - break; - - case TRANS_STMT_COMMIT: - { - if (exec_state_call_stack && - exec_state_call_stack->estate && - exec_state_call_stack->estate->insert_exec && - NestedTranCount <= 1) - ereport(ERROR, - (errcode(ERRCODE_TRANSACTION_ROLLBACK), - errmsg("Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first."))); - - PLTsqlCommitTransaction(qc, stmt->chain); - } - break; - - case TRANS_STMT_ROLLBACK: - { - if (exec_state_call_stack && - exec_state_call_stack->estate && - exec_state_call_stack->estate->insert_exec) - 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. - */ - if (exec_state_call_stack && - exec_state_call_stack->estate && - exec_state_call_stack->estate->func && - list_length(exec_state_call_stack->estate->func->table_varnos) > 0) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("ROLLBACK statement with active table variables is not yet supported."))); - PLTsqlRollbackTransaction(txnName, qc, stmt->chain); - } - break; - - case TRANS_STMT_SAVEPOINT: - RequireTransactionBlock(true, "SAVEPOINT"); - DefineSavepoint(txnName); - break; - - default: - ereport(ERROR, - (errcode(ERRCODE_INVALID_TRANSACTION_INITIATION), - errmsg("Unsupported transaction command : %d", stmt->kind))); - break; - } -} - /* * It returns TRUE when we should not execute the utility statement, * e.g., CREATE FUNCTION, in EXPLAIN ONLY MODE. @@ -1905,13 +2102,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; @@ -1934,8 +2132,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; @@ -1947,11 +2147,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))); } @@ -1961,27 +2162,43 @@ 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 */ + { + if (qc && parsetree) { + /* + * Some utility statements return a row count, even though the + * tuples are not returned to the caller. + */ + Assert(qc->commandTag == CMDTAG_UNKNOWN); + if (IsA(parsetree, CreateTableAsStmt)) + SetQueryCompletion(qc, CMDTAG_SELECT, 0); + else if (IsA(parsetree, CopyStmt)) + SetQueryCompletion(qc, CMDTAG_COPY, 0); + } + + 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) @@ -1989,64 +2206,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; } @@ -2054,1101 +2278,1124 @@ static void bbf_ProcessUtility(PlannedStmt *pstmt, switch (nodeTag(parsetree)) { - case T_CreateFunctionStmt: + case T_AlterTableStmt: { - 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 */ - needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery(); - - /* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */ - PG_TRY(); - { - if (isCompleteQuery) - EventTriggerDDLCommandStart(parsetree); + AlterTableStmt *atstmt = (AlterTableStmt *) parsetree; + ListCell *lc; - foreach (option, stmt->options) + if (sql_dialect == SQL_DIALECT_TSQL) + { + foreach(lc, atstmt->cmds) { - 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 = defel->arg; - } - else if (strcmp(defel->defname, "trigStmt") == 0) + AlterTableCmd *cmd = (AlterTableCmd *)lfirst(lc); + if (cmd->subtype == AT_EnableTrig || cmd->subtype == AT_DisableTrig) { - /* - * trigStmt is an implicit option in tsql dialect, - * we use this mechanism to create tsql style function - * and trigger in one statement. - */ - trigStmt = defel->arg; - } - else if (strcmp(defel->defname, "location") == 0) - { - /* - * 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. - */ - origname_location = intVal((Node *) defel->arg); - location_cell = option; - pfree(defel); - } - } - - /* 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); - - /* - * For tbltypStmt, we need to first process the CreateStmt - * to create the type that will be used as the function's - * return type. Then, after the function is created, add a - * dependency between the type and the function. - */ - if (tbltypStmt) - { - /* Handle tbltypStmt, which is a CreateStmt */ - PlannedStmt *wrapper; - - wrapper = makeNode(PlannedStmt); - wrapper->commandType = CMD_UTILITY; - wrapper->canSetTag = false; - wrapper->utilityStmt = tbltypStmt; - wrapper->stmt_location = pstmt->stmt_location; - wrapper->stmt_len = pstmt->stmt_len; - - ProcessUtility(wrapper, - queryString, - readOnlyTree, - PROCESS_UTILITY_SUBCOMMAND, - params, - NULL, - None_Receiver, - NULL); - - /* Need CCI between commands */ - CommandCounterIncrement(); - } - - address = CreateFunction(pstate, stmt); - - /* Store function/procedure related metadata in babelfish catalog */ - pltsql_store_func_default_positions(address, stmt->parameters, queryString, origname_location); - - if (tbltypStmt || restore_tsql_tabletype) - { - /* - * Add internal dependency between the table type and - * the function. - */ - tbltyp.classId = TypeRelationId; - tbltyp.objectId = typenameTypeId(pstate, - 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 - * dependency so that Drop Trigger CASCADE will drop the - * implicit trigger function. - * Create trigger takes care of dependency addition. - */ - if(trigStmt) - { - (void) CreateTrigger((CreateTrigStmt *) trigStmt, - 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. - */ - EventTriggerCollectSimpleCommand(address, InvalidObjectAddress, - parsetree); + if (atstmt->relation->schemaname != NULL) + { + /* + * As syntax1 ( { ENABLE | DISABLE } TRIGGER ON
) + * is mapped to syntax2 ( ALTER TABLE
{ ENABLE | DISABLE } TRIGGER ), + * objtype of atstmt for syntax1 is temporarily set to OBJECT_TRIGGER to identify whether the + * query was originally of syntax1 or syntax2, here astmt->objtype is reset back to OBJECT_TABLE + */ + if (atstmt->objtype == OBJECT_TRIGGER) + { + int16 dbid = get_cur_db_id(); + int16 stmt_dbid = get_dbid_from_physical_schema_name(atstmt->relation->schemaname, true); - if (isCompleteQuery) - { - EventTriggerSQLDrop(parsetree); - EventTriggerDDLCommandEnd(parsetree); + if (dbid != stmt_dbid) /* Check to identify cross-db referencing */ + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Cannot %s trigger on '%s.%s.%s' as the target is not in the current database." + , cmd->subtype == AT_EnableTrig ? "enable" : "disable", get_db_name(stmt_dbid), get_logical_schema_name(atstmt->relation->schemaname, true), atstmt->relation->relname))); + } + atstmt->objtype = OBJECT_TABLE; + } + } + } } - } - PG_CATCH(); - { - if (needCleanup) - EventTriggerEndCompleteQuery(); - PG_RE_THROW(); - } - PG_END_TRY(); - - if (needCleanup) - EventTriggerEndCompleteQuery(); - 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; + DefElem *headel = (DefElem *) linitial(stmt->options); - 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) + /* + * 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; - if (strcmp(defel->defname, "default_database") == 0) - login_options = lappend(login_options, defel); - else if (strcmp(defel->defname, "name_location") == 0) + 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) { - int location = defel->location; - orig_loginname = extract_identifier(queryString + location); - login_options = lappend(login_options, defel); + 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); + } } - else if (strcmp(defel->defname, "from_windows") == 0) + + foreach(option, login_options) { - 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); + stmt->options = list_delete_ptr(stmt->options, + lfirst(option)); } - } - foreach(option, login_options) - { - stmt->options = list_delete_ptr(stmt->options, - lfirst(option)); - } + if (orig_loginname) + { + login_options = lappend(login_options, + makeDefElem("original_login_name", + (Node *) makeString(orig_loginname), + -1)); + } - if (orig_loginname) - { - login_options = lappend(login_options, - makeDefElem("original_login_name", - (Node *) makeString(orig_loginname), - -1)); - } + 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 (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 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 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 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 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))); + + /* + * 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); + + /* + * 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; + 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)); + 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(); + + return; } - PG_END_TRY(); + else if (isuser || isrole) + { + /* + * check whether sql user name and role name contains + * '\' or not + */ + if (isrole || !from_windows) + validateUserAndRole(stmt->role); - 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); + /* 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); + else if (strcmp(defel->defname, "rename") == 0) + 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) + { + /* + * 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; + } + 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)); + } + } + 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; + + datdba = get_role_oid("sysadmin", false); - /* Filter user options from default role options */ + /* + * 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 (get_role_oid(stmt->role->rolename, true) != GetSessionUserId() && !is_member_of_role(GetSessionUserId(), datdba)) + ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot alter the login '%s', because it does not exist or you do not have permission.", stmt->role->rolename))); - 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 (!has_privs_of_role(GetSessionUserId(), datdba) && !has_password) + ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Cannot alter the login '%s', because it does not exist or you do not have permission.", 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(); - - SetCurrentRoleId(prev_current_user, false); - - return; - } - else if (isuser || isrole) - { - const char *db_name; - const char *dbo_name; - Oid dbo_id; + 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(); - db_name = get_cur_db_name(); - dbo_name = get_dbo_role_name(db_name); - dbo_id = get_role_oid(dbo_name, false); + SetCurrentRoleId(prev_current_user, false); - /* - * Check if the current user has privileges. - */ - foreach(option, user_options) + return; + } + else if (isuser || isrole) { - DefElem *defel = (DefElem *) lfirst(option); - char *user_name; - char *cur_user; + const char *dbo_name; + char *db_name; + char *user_name; + char *cur_user; + Oid dbo_id; + 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) + + /* + * Check if the current user has privileges. + */ + foreach(option, user_options) { - 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"))); + DefElem *defel = (DefElem *) lfirst(option); + + 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"))); + } + else 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"))); + } } - if (strcmp(defel->defname, "rename") == 0) + + foreach(option, stmt->options) { - 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"))); + DefElem *defel = (DefElem *) lfirst(option); + + if (strcmp(defel->defname, "rolemembers") == 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 login"))); + } } - } - /* Set current user to dbo for alter permissions */ - SetCurrentRoleId(dbo_id, false); + /* 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, + 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(); + 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(); - SetCurrentRoleId(prev_current_user, false); - set_session_properties(db_name); + SetCurrentRoleId(prev_current_user, false); + set_session_properties(db_name); + pfree(cur_user); + pfree(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 drop_login = 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; + else + drop_login = 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); + if (drop_login && is_login(roleform->oid) && !has_privs_of_role(GetSessionUserId(), get_role_oid("sysadmin", false))){ + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + 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"))); - } + ReleaseSysCache(tuple); - /* 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; + RoleSpec *rolspec = create_schema->authrole; + + 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; + 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(); + /* Grant all privileges to the user.*/ + if (rolspec && strcmp(queryString, "(CREATE LOGICAL DATABASE )") != 0) + { + char *permissions[] = {"select", "insert", "update", "references", "delete", "execute"}; + List *parsetree_list; + ListCell *parsetree_item; + int i; + for (i = 0; i < 6; i++) + { + parsetree_list = gen_grantschema_subcmds(create_schema->schemaname, rolspec->rolename, true, false, permissions[i]); + /* Run all subcommands */ + foreach(parsetree_item, parsetree_list) + { + Node *stmt = ((RawStmt *) lfirst(parsetree_item))->stmt; + PlannedStmt *wrapper; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = 0; + + /* do this step */ + ProcessUtility(wrapper, + "(GRANT SCHEMA )", + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + } + } + } + return; + } + else + break; } - else - break; - } case T_DropStmt: - { - DropStmt *drop_stmt = (DropStmt *) parsetree; - if (drop_stmt->removeType != OBJECT_SCHEMA) - break; - - if (sql_dialect == SQL_DIALECT_TSQL) { - // 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) { - char *cur_db = get_cur_db_name(); - char *guest_schema_name = get_physical_schema_name(cur_db, "guest"); + if (sql_dialect == SQL_DIALECT_TSQL) + bbf_ExecDropStmt(drop_stmt); + break; + } - if (strcmp(schemaname, guest_schema_name) == 0) { - ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Cannot drop the schema \'%s\'", schemaname))); + + if (sql_dialect == SQL_DIALECT_TSQL) + { + /* + * Prevent dropping guest schema unless it is part of drop + * database command. + */ + const char *schemaname = strVal(lfirst(list_head(drop_stmt->objects))); + char *cur_db = get_cur_db_name(); + const char *logicalschema = get_logical_schema_name(schemaname, true); + + if (strcmp(queryString, "(DROP DATABASE )") != 0) + { + 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); + bbf_ExecDropStmt(drop_stmt); + del_ns_ext_info(schemaname, drop_stmt->missing_ok); + if (logicalschema != NULL) + clean_up_bbf_schema(logicalschema, NULL, true); - 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; - } - } - case T_CreatedbStmt: - if (sql_dialect == SQL_DIALECT_TSQL) - { - create_bbf_db(pstate, (CreatedbStmt *) 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; + } } - break; - case T_DropdbStmt: - if (sql_dialect == SQL_DIALECT_TSQL) - { - DropdbStmt *stmt = (DropdbStmt *) parsetree; - drop_bbf_db(stmt->dbname, stmt->missing_ok, false); - return; - } - 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); @@ -3160,10 +3407,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(); @@ -3179,8 +3426,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); @@ -3191,10 +3438,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(); @@ -3211,105 +3458,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 *) palloc0(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) @@ -3324,44 +3573,308 @@ 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; } + case T_VariableSetStmt: + { + VariableSetStmt *variable_set = (VariableSetStmt *) parsetree; + + if(strcmp(variable_set->name, "SESSION CHARACTERISTICS") == 0) + { + ListCell *head; + + foreach(head, variable_set->args) + { + DefElem *item = (DefElem *) lfirst(head); + A_Const *isolation_level = (A_Const *) item->arg; + + if(strcmp(item->defname, "transaction_isolation") == 0) + { + bbf_set_tran_isolation(strVal(&isolation_level->val)); + return; + } + } + } + break; + } + case T_GrantStmt: + { + GrantStmt *grant = (GrantStmt *) parsetree; + char *dbname = get_cur_db_name(); + const char *current_user = GetUserNameFromId(GetUserId(), false); + /* Ignore when GRANT statement has no specific named object. */ + if (sql_dialect != SQL_DIALECT_TSQL || grant->targtype != ACL_TARGET_OBJECT) + break; + Assert(list_length(grant->objects) == 1); + if (grant->objtype == OBJECT_SCHEMA) + break; + else if (grant->objtype == OBJECT_TABLE) + { + /* Ignore CREATE database subcommands */ + if (strcmp("(CREATE LOGICAL DATABASE )", queryString) != 0) + { + RangeVar *rv = (RangeVar *) linitial(grant->objects); + const char *logical_schema = NULL; + char *obj = rv->relname; + ListCell *lc; + ListCell *lc1; + const char *obj_type = "r"; + if (rv->schemaname != NULL) + logical_schema = get_logical_schema_name(rv->schemaname, true); + else + logical_schema = get_authid_user_ext_schema_name(dbname, current_user); + /* If ALL PRIVILEGES is granted/revoked. */ + if (list_length(grant->privileges) == 0) + { + if (grant->is_grant) + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + int i = 0; + char *permissions[] = {"select", "insert", "update", "references", "delete"}; + for(i = 0; i < 5; i++) + { + if ((rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logical_schema, obj, permissions[i], rol_spec->rolename)) + add_entry_to_bbf_schema(logical_schema, obj, permissions[i], rol_spec->rolename, obj_type); + } + } + break; + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + int i = 0; + bool has_schema_perms = false; + char *permissions[] = {"select", "insert", "update", "references", "delete"}; + for(i = 0; i < 5; i++) + { + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logical_schema, "ALL", permissions[i], rol_spec->rolename) && !has_schema_perms) + has_schema_perms = true; + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logical_schema, obj, permissions[i], rol_spec->rolename)) + del_from_bbf_schema(logical_schema, obj, permissions[i], rol_spec->rolename); + } + if (has_schema_perms) + return; + } + break; + } + } + foreach(lc1, grant->privileges) + { + AccessPriv *ap = (AccessPriv *) lfirst(lc1); + if (grant->is_grant) + { + /* + * 1. Execute the GRANT statement. + * 2. Add its corresponding entry in the catalog, if doesn't exist already. + * 3. Don't add an entry, if the permission is granted on column list. + */ + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + else + standard_ProcessUtility(pstmt, queryString, readOnlyTree, context, params, + queryEnv, dest, qc); + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if ((ap->cols == NULL) && (rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logical_schema, obj, ap->priv_name, rol_spec->rolename)) + add_entry_to_bbf_schema(logical_schema, obj, ap->priv_name, rol_spec->rolename, obj_type); + } + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* + * 1. If GRANT on schema does not exist, execute REVOKE statement and remove the catalog entry if exists. + * 2. If GRANT on schema exist, only remove the entry from the catalog if exists. + */ + if ((logical_schema != NULL) && (rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logical_schema, "ALL", ap->priv_name, rol_spec->rolename)) + { + 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 ((ap->cols == NULL) && (rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logical_schema, obj, ap->priv_name, rol_spec->rolename)) + del_from_bbf_schema(logical_schema, obj, ap->priv_name, rol_spec->rolename); + } + } + } + return; + } + } + else if ((grant->objtype == OBJECT_PROCEDURE) || (grant->objtype == OBJECT_FUNCTION)) + { + ObjectWithArgs *ob = (ObjectWithArgs *) linitial(grant->objects); + ListCell *lc; + ListCell *lc1; + const char *logicalschema = NULL; + char *funcname = NULL; + const char *obj_type = NULL; + if (grant->objtype == OBJECT_FUNCTION) + obj_type = "f"; + else + obj_type = "p"; + if (list_length(ob->objname) == 1) + { + Node *func = (Node *) linitial(ob->objname); + funcname = strVal(func); + logicalschema = get_authid_user_ext_schema_name(dbname, current_user); + } + else + { + Node *schema = (Node *) linitial(ob->objname); + char *schemaname = strVal(schema); + Node *func = (Node *) lsecond(ob->objname); + logicalschema = get_logical_schema_name(schemaname, true); + funcname = strVal(func); + } + /* + * Case: When ALL PRIVILEGES is revoked internally during create function. + * Check if schema entry exists in the catalog, do not revoke any permission if exists. + */ + if (pstmt->stmt_len == 0 && list_length(grant->privileges) == 0) + { + if(check_bbf_schema_for_schema(logicalschema, "ALL", "execute")) + return; + break; + } + /* If ALL PRIVILEGES is granted/revoked. */ + if (list_length(grant->privileges) == 0) + { + if (grant->is_grant) + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + if ((rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logicalschema, funcname, "execute", rol_spec->rolename)) + add_entry_to_bbf_schema(logicalschema, funcname, "execute", rol_spec->rolename, obj_type); + } + break; + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + bool has_schema_perms = false; + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logicalschema, "ALL", "execute", rol_spec->rolename) && !has_schema_perms) + has_schema_perms = true; + if ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logicalschema, funcname, "execute", rol_spec->rolename)) + del_from_bbf_schema(logicalschema, funcname, "execute", rol_spec->rolename); + if (has_schema_perms) + return; + } + break; + } + } + foreach(lc1, grant->privileges) + { + AccessPriv *ap = (AccessPriv *) lfirst(lc1); + if (grant->is_grant) + { + /* Execute the GRANT statement. */ + 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 entry to the catalog if it doesn't exist already. */ + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* Don't store a row in catalog, if permission is granted for column */ + if ((rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logicalschema, funcname, ap->priv_name, rol_spec->rolename)) + add_entry_to_bbf_schema(logicalschema, funcname, ap->priv_name, rol_spec->rolename, obj_type); + } + } + else + { + foreach(lc, grant->grantees) + { + RoleSpec *rol_spec = (RoleSpec *) lfirst(lc); + /* + * 1. If GRANT on schema does not exist, execute REVOKE statement and remove the catalog entry if exists. + * 2. If GRANT on schema exist, only remove the entry from the catalog if exists. + */ + if ((rol_spec->rolename != NULL) && !check_bbf_schema_for_entry(logicalschema, "ALL", ap->priv_name, rol_spec->rolename)) + { + /* Execute REVOKE statement. */ + 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 ((rol_spec->rolename != NULL) && check_bbf_schema_for_entry(logicalschema, funcname, ap->priv_name, rol_spec->rolename)) + del_from_bbf_schema(logicalschema, funcname, ap->priv_name, rol_spec->rolename); + } + } + } + return; + } + } default: break; } 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); + + /* Cleanup babelfish_server_options catalog when tds_fdw extension is dropped */ + if (sql_dialect == SQL_DIALECT_PG && nodeTag(parsetree) == T_DropStmt) + { + DropStmt *drop_stmt = (DropStmt *) parsetree; + if (drop_stmt != NULL && drop_stmt->removeType == OBJECT_EXTENSION) + { + char *ext_name = strVal(lfirst(list_head(drop_stmt->objects))); + if ((strcmp(ext_name, "tds_fdw") == 0) && drop_stmt->behavior == DROP_CASCADE) + { + clean_up_bbf_server_def(); + } + } + } } /* * 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); @@ -3390,28 +3903,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))); @@ -3432,22 +3947,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 @@ -3455,8 +3974,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); @@ -3467,7 +3986,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); } @@ -3475,6 +3996,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; @@ -3485,29 +4007,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_TEXT_P(cstring_to_text(name)); } @@ -3522,8 +4044,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; @@ -3534,13 +4056,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", @@ -3553,23 +4075,23 @@ _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, + check_identity_insert, assign_identity_insert, NULL); @@ -3610,14 +4132,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"); @@ -3633,14 +4155,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) @@ -3648,12 +4170,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; @@ -3744,8 +4266,6 @@ _PG_init(void) pltsql_setval_hook = pltsql_setval_identity; suppress_string_truncation_error_hook = pltsql_suppress_string_truncation_error; - - pre_function_call_hook = pre_function_call_hook_impl; prev_relname_lookup_hook = relname_lookup_hook; relname_lookup_hook = bbf_table_var_lookup; prev_ProcessUtility = ProcessUtility_hook; @@ -3757,7 +4277,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; } @@ -3777,6 +4298,8 @@ _PG_init(void) get_func_language_oids_hook = get_func_language_oids; coalesce_typmod_hook = coalesce_typmod_hook_impl; + check_pltsql_support_tsql_transactions_hook = pltsql_support_tsql_transactions; + inited = true; } @@ -3814,10 +4337,13 @@ _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; + + HOLD_INTERRUPTS(); elog(DEBUG2, "TSQL TXN finish current batch, error : %d compilation error : %d", send_error, compile_error); @@ -3829,8 +4355,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); @@ -3854,8 +4381,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(); @@ -3869,15 +4397,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(); @@ -3887,22 +4416,28 @@ static void terminate_batch(bool send_error, bool compile_error) AbortCurTransaction = false; if (!send_error) + { + RESUME_INTERRUPTS(); ereport(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); } } + + RESUME_INTERRUPTS(); if (send_error) { PG_RE_THROW(); @@ -3910,12 +4445,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 @@ -3952,18 +4488,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); @@ -3975,12 +4511,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) @@ -3997,9 +4533,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; @@ -4019,25 +4555,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 @@ -4052,11 +4593,10 @@ pltsql_call_handler(PG_FUNCTION_ARGS) pltsql_trigger_depth = save_pltsql_trigger_depth; func->use_count--; func->cur_estate = save_cur_estate; - ENRDropTempTables(currentQueryEnv); - remove_queryEnv(); + pltsql_remove_current_query_env(); 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; } @@ -4072,12 +4612,11 @@ pltsql_call_handler(PG_FUNCTION_ARGS) func->cur_estate = save_cur_estate; - ENRDropTempTables(currentQueryEnv); - remove_queryEnv(); + pltsql_remove_current_query_env(); 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; } @@ -4092,26 +4631,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; @@ -4130,7 +4670,7 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) codeblock_args = (InlineCodeBlockArgs *) DatumGetPointer(PG_GETARG_DATUM(1)); sql_dialect = SQL_DIALECT_TSQL; - + /* * Connect to SPI manager */ @@ -4153,7 +4693,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++; } @@ -4170,9 +4710,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)); @@ -4184,10 +4725,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 @@ -4218,12 +4760,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); @@ -4248,15 +4790,19 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) rsinfo.isDone = ExprSingleResult; rsinfo.setResult = NULL; rsinfo.setDesc = NULL; + ReleaseTupleDesc(reldesc); } /* 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; @@ -4271,8 +4817,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 ... */ @@ -4288,7 +4834,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(); @@ -4296,13 +4842,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)) @@ -4310,6 +4857,7 @@ pltsql_inline_handler(PG_FUNCTION_ARGS) dest->receiveSlot(slot, dest); ExecClearTuple(slot); } + ReleaseTupleDesc(rsinfo.expectedDesc); ExecDropSingleTupleTableSlot(slot); } @@ -4324,8 +4872,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; } @@ -4352,12 +4900,17 @@ 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_mstvf = false; + MemoryContext oldMemoryContext = CurrentMemoryContext; - int saved_dialect = sql_dialect; + int saved_dialect = sql_dialect; if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) PG_RETURN_VOID(); @@ -4368,16 +4921,18 @@ 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) || - (*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); @@ -4420,21 +4975,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) { @@ -4477,24 +5032,39 @@ 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); + 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 */ @@ -4505,14 +5075,12 @@ pltsql_validator(PG_FUNCTION_ARGS) ReleaseSysCache(tuple); /* - * 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. + * 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 (is_itvf && !babelfish_dump_restore) + if(prokind == PROKIND_FUNCTION && (has_table_var && !is_itvf && !is_mstvf)) { - SPIPlanPtr spi_plan; - int spi_rc; Relation rel; HeapTuple tup; HeapTuple oldtup; @@ -4520,22 +5088,64 @@ pltsql_validator(PG_FUNCTION_ARGS) 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; + 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 + * 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; 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); @@ -4543,7 +5153,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); @@ -4584,14 +5194,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) { @@ -4606,8 +5216,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) @@ -4621,15 +5231,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; @@ -4644,10 +5254,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) { @@ -4657,7 +5267,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, @@ -4701,7 +5311,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)) { @@ -4791,75 +5401,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); @@ -4877,7 +5487,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) { @@ -4885,107 +5495,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); @@ -4996,7 +5608,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; @@ -5010,6 +5622,253 @@ pltsql_revert_guc(int nest_level) } +static char * +get_oid_type_string(int type_oid) +{ + char *type_string = NULL; + if ((*common_utility_plugin_ptr->is_tsql_decimal_datatype) (type_oid)) + { + type_string = "decimal"; + return type_string; + } + + switch(type_oid) + { + case INT2OID: + type_string = "pg_catalog.int2"; + break; + case INT4OID: + type_string = "pg_catalog.int4"; + break; + case INT8OID: + type_string = "pg_catalog.int8"; + break; + case NUMERICOID: + type_string = "pg_catalog.numeric"; + break; + default: + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("A user-defined data type for an IDENTITY column is not currently supported"))); + break; + } + return type_string; +} + +static int64 +get_identity_into_args(Node *node) +{ + int64 val = 0; + Const *con = NULL; + FuncExpr *fxpr = NULL; + OpExpr *opxpr = NULL; + Node *n = NULL; + + switch (nodeTag(node)) + { + case T_Const: + con = (Const *)node; + val = (int64)DatumGetInt64(con->constvalue); + break; + case T_FuncExpr: + fxpr = (FuncExpr *)node; + if ((fxpr->args)->length != 1) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error near 'identity'"))); + n = (Node *)list_nth(fxpr->args, 0); + val = get_identity_into_args(n); + break; + case T_OpExpr: + opxpr = (OpExpr *)node; + if ((opxpr->args)->length != 1) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error near 'identity'"))); + n = (Node *)list_nth(opxpr->args, 0); + val = get_identity_into_args(n); + break; + default: + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax error near 'identity'"))); + break; + } + return val; +} + +static List * +transformSelectIntoStmt(CreateTableAsStmt *stmt) +{ + List *result; + ListCell *elements; + AlterTableStmt *altstmt; + IntoClause *into; + Node *n; + + n = stmt->query; + into = stmt->into; + result = NIL; + altstmt = NULL; + + if (n && n->type == T_Query) + { + Query *q = (Query *)n; + bool seen_identity = false; + AttrNumber current_resno = 0; + Index identity_ressortgroupref = 0; + List *modifiedTargetList = NIL; + + foreach (elements, q->targetList) + { + TargetEntry *tle = (TargetEntry *)lfirst(elements); + + if (tle->expr && IsA(tle->expr, FuncExpr) && strcasecmp(get_func_name(((FuncExpr *)(tle->expr))->funcid), "identity_into_bigint") == 0) + { + FuncExpr *funcexpr; + List *seqoptions = NIL; + ListCell *arg; + int typeoid = 0; + + TypeName *typename = NULL; + int64 seedvalue = 0, incrementvalue = 0; + int argnum; + AlterTableCmd *lcmd; + ColumnDef *def; + Constraint *constraint; + + if (seen_identity) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Attempting to add multiple identity columns to table \"%s\" using the SELECT INTO statement.", into->rel->relname))); + + if (tle->resname == NULL) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Incorrect syntax near the keyword 'INTO'"))); + + funcexpr = (FuncExpr *)tle->expr; + argnum = 0; + foreach (arg, funcexpr->args) + { + Node *farg_node = (Node *)lfirst(arg); + argnum++; + switch (argnum) + { + case 1: + typeoid = get_identity_into_args(farg_node); + typename = typeStringToTypeName(get_oid_type_string(typeoid)); + break; + case 2: + seedvalue = get_identity_into_args(farg_node); + seqoptions = lappend(seqoptions, makeDefElem("start", (Node *)makeFloat(psprintf(INT64_FORMAT, seedvalue)), -1)); + break; + case 3: + incrementvalue = get_identity_into_args(farg_node); + seqoptions = lappend(seqoptions, makeDefElem("increment", (Node *)makeFloat(psprintf(INT64_FORMAT, incrementvalue)), -1)); + if (incrementvalue > 0) + { + seqoptions = lappend(seqoptions, makeDefElem("minvalue", (Node *)makeFloat(psprintf(INT64_FORMAT, seedvalue)), -1)); + } + else + { + seqoptions = lappend(seqoptions, makeDefElem("maxvalue", (Node *)makeFloat(psprintf(INT64_FORMAT, seedvalue)), -1)); + } + break; + } + } + + seen_identity = true; + identity_ressortgroupref = tle->ressortgroupref; /** Save this Index to modify sortClause and distinctClause*/ + + /** Add alter table add identity node after Select Into statement */ + altstmt = makeNode(AlterTableStmt); + altstmt->relation = into->rel; + altstmt->cmds = NIL; + + constraint = makeNode(Constraint); + constraint->contype = CONSTR_IDENTITY; + constraint->generated_when = ATTRIBUTE_IDENTITY_ALWAYS; + constraint->options = seqoptions; + + def = makeNode(ColumnDef); + def->colname = tle->resname; + def->typeName = typename; + def->identity = ATTRIBUTE_IDENTITY_ALWAYS; + def->is_not_null = true; + def->constraints = lappend(def->constraints, constraint); + + lcmd = makeNode(AlterTableCmd); + lcmd->subtype = AT_AddColumn; + lcmd->missing_ok = false; + lcmd->def = (Node *)def; + altstmt->cmds = lappend(altstmt->cmds, lcmd); + } + else + { + current_resno += 1; + tle->resno = current_resno; + modifiedTargetList = lappend(modifiedTargetList, tle); + } + } + q->targetList = modifiedTargetList; + + if (seen_identity) + { + if (q->sortClause) + { + List *modifiedSortClause = NIL; + ListCell *olitem; + foreach (olitem, q->sortClause) + { + Node *sortnode = (Node *)lfirst(olitem); + if (IsA(sortnode, SortGroupClause)) + { + SortGroupClause *sortcl = (SortGroupClause *)sortnode; + if (sortcl->tleSortGroupRef != identity_ressortgroupref) + modifiedSortClause = lappend(modifiedSortClause, sortcl); + } + } + q->sortClause = modifiedSortClause; + } + + if (q->distinctClause && list_length(q->distinctClause) > (identity_ressortgroupref - 1)) + q->distinctClause = list_delete_nth_cell(q->distinctClause, identity_ressortgroupref - 1); + } + } + + result = lappend(result, stmt); + if (altstmt) + result = lappend(result, altstmt); + + return result; +} + +void pltsql_bbfSelectIntoUtility(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, QueryEnvironment *queryEnv, + ParamListInfo params, QueryCompletion *qc) +{ + + Node *parsetree = pstmt->utilityStmt; + ObjectAddress address; + ObjectAddress secondaryObject = InvalidObjectAddress; + List *stmts; + stmts = transformSelectIntoStmt((CreateTableAsStmt *)parsetree); + while (stmts != NIL) + { + Node *stmt = (Node *)linitial(stmts); + stmts = list_delete_first(stmts); + if (IsA(stmt, CreateTableAsStmt)) + { + address = ExecCreateTableAs(pstate, (CreateTableAsStmt *)parsetree, params, queryEnv, qc); + EventTriggerCollectSimpleCommand(address, secondaryObject, stmt); + } + else + { + PlannedStmt *wrapper; + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + + ProcessUtility(wrapper, queryString, false, PROCESS_UTILITY_SUBCOMMAND, params, NULL, None_Receiver, NULL); + } + if (stmts != NIL) + CommandCounterIncrement(); + } +} + void set_current_query_is_create_tbl_check_constraint(Node *expr) { @@ -5018,12 +5877,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; @@ -5031,3 +5891,204 @@ set_current_query_is_create_tbl_check_constraint(Node *expr) } } } + +void +pltsql_remove_current_query_env(void) +{ + ENRDropTempTables(currentQueryEnv); + remove_queryEnv(); + + if (!currentQueryEnv || + (currentQueryEnv == topLevelQueryEnv && get_namedRelList() == NIL)) + { + destroy_failed_transactions_map(); + } +} + +/* + * Drop statement of babelfish, currently delete extended property as well. + */ +static void +bbf_ExecDropStmt(DropStmt *stmt) +{ + int16 db_id; + const char *type = NULL; + char *schema_name = NULL, + *major_name = NULL; + ObjectAddress address; + Relation relation = NULL; + Oid schema_oid; + ListCell *cell; + const char *logicalschema = NULL; + + db_id = get_cur_db_id(); + + if (stmt->removeType == OBJECT_SCHEMA) + { + foreach(cell, stmt->objects) + { + schema_name = strVal(lfirst(cell)); + + if (get_namespace_oid(schema_name, true) == InvalidOid) + return; + + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SCHEMA]; + delete_extended_property(db_id, type, schema_name, NULL, NULL); + } + } + else if (stmt->removeType == OBJECT_TABLE || + stmt->removeType == OBJECT_VIEW || + stmt->removeType == OBJECT_SEQUENCE) + { + foreach(cell, stmt->objects) + { + relation = NULL; + address = get_object_address(stmt->removeType, + lfirst(cell), + &relation, + AccessShareLock, + true); + + if (!relation) + continue; + + /* Get major_name */ + major_name = pstrdup(RelationGetRelationName(relation)); + relation_close(relation, AccessShareLock); + + /* Get schema_name */ + schema_oid = get_object_namespace(&address); + if (OidIsValid(schema_oid)) + schema_name = get_namespace_name(schema_oid); + if (schema_name != NULL) + logicalschema = get_logical_schema_name(schema_name, true); + + if (schema_name && major_name) + { + if (stmt->removeType == OBJECT_TABLE) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE]; + delete_extended_property(db_id, type, schema_name, + major_name, NULL); + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE_COLUMN]; + delete_extended_property(db_id, type, schema_name, + major_name, NULL); + } + else if (stmt->removeType == OBJECT_VIEW) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_VIEW]; + delete_extended_property(db_id, type, schema_name, + major_name, NULL); + } + else if (stmt->removeType == OBJECT_SEQUENCE) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SEQUENCE]; + delete_extended_property(db_id, type, schema_name, + major_name, NULL); + } + } + if (logicalschema != NULL) + clean_up_bbf_schema(logicalschema, major_name, false); + } + } + else if (stmt->removeType == OBJECT_PROCEDURE || + stmt->removeType == OBJECT_FUNCTION || + stmt->removeType == OBJECT_TYPE) + { + HeapTuple tuple; + + foreach(cell, stmt->objects) + { + relation = NULL; + address = get_object_address(stmt->removeType, + lfirst(cell), + &relation, + AccessShareLock, + true); + Assert(relation == NULL); + if (!OidIsValid(address.objectId)) + continue; + + /* Get major_name */ + relation = table_open(address.classId, AccessShareLock); + tuple = get_catalog_object_by_oid(relation, + get_object_attnum_oid(address.classId), + address.objectId); + if (!HeapTupleIsValid(tuple)) + { + table_close(relation, AccessShareLock); + continue; + } + + if (stmt->removeType == OBJECT_PROCEDURE || + stmt->removeType == OBJECT_FUNCTION) + major_name = pstrdup(NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname)); + else if (stmt->removeType == OBJECT_TYPE) + major_name = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(tuple))->typname)); + + table_close(relation, AccessShareLock); + + /* Get schema_name */ + schema_oid = get_object_namespace(&address); + if (OidIsValid(schema_oid)) + schema_name = get_namespace_name(schema_oid); + if (schema_name != NULL) + logicalschema = get_logical_schema_name(schema_name, true); + + if (schema_name && major_name) + { + if (stmt->removeType == OBJECT_PROCEDURE) + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_PROCEDURE]; + else if (stmt->removeType == OBJECT_FUNCTION) + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_FUNCTION]; + else if (stmt->removeType == OBJECT_TYPE) + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TYPE]; + + delete_extended_property(db_id, type, schema_name, major_name, + NULL); + } + if (logicalschema != NULL) + clean_up_bbf_schema(logicalschema, major_name, false); + } + } +} + +static int +isolation_to_int(char *isolation_level) +{ + if (strcmp(isolation_level, "serializable") == 0) + return XACT_SERIALIZABLE; + else if (strcmp(isolation_level, "repeatable read") == 0) + return XACT_REPEATABLE_READ; + else if (strcmp(isolation_level, "read committed") == 0) + return XACT_READ_COMMITTED; + else if (strcmp(isolation_level, "read uncommitted") == 0) + return XACT_READ_UNCOMMITTED; + + return 0; +} + +static void +bbf_set_tran_isolation(char *new_isolation_level_str) +{ + const int new_isolation_int_val = isolation_to_int(new_isolation_level_str); + + if(new_isolation_int_val != DefaultXactIsoLevel) + { + if(FirstSnapshotSet || IsSubTransaction() || + (new_isolation_int_val == XACT_SERIALIZABLE && RecoveryInProgress())) + { + if(escape_hatch_set_transaction_isolation_level == EH_IGNORE) + return; + else + elog(ERROR, "SET TRANSACTION ISOLATION failed, transaction aborted, set escape hatch " + "'escape_hatch_set_transaction_isolation_level' to ignore such error"); + } + else + { + SetConfigOption("transaction_isolation", new_isolation_level_str, PGC_USERSET, PGC_S_SESSION); + SetConfigOption("default_transaction_isolation", new_isolation_level_str, PGC_USERSET, PGC_S_SESSION); + } + } + return ; +} 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..4d2b259f58 100644 --- a/contrib/babelfishpg_tsql/src/plerrcodes.h +++ b/contrib/babelfishpg_tsql/src/plerrcodes.h @@ -1006,5 +1006,4 @@ { "pltsql_error_not_mapped", ERRCODE_PLTSQL_ERROR_NOT_MAPPED -}, - +}, \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/pltsql-2.h b/contrib/babelfishpg_tsql/src/pltsql-2.h index fbaafb422a..634640d3c0 100644 --- a/contrib/babelfishpg_tsql/src/pltsql-2.h +++ b/contrib/babelfishpg_tsql/src/pltsql-2.h @@ -7,21 +7,32 @@ */ 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; +/* + * KILL statement + */ +typedef struct +{ + PLtsql_stmt_type cmd_type; + int lineno; + char *label; + int spid; +} PLtsql_stmt_kill; + /* * init statement */ 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 +40,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 +64,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 +75,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 +125,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 +150,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 +203,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 +228,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 +241,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 +255,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 +265,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 +275,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 +286,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 +295,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 15a81909c7..ae94b0ddf1 100644 --- a/contrib/babelfishpg_tsql/src/pltsql.h +++ b/contrib/babelfishpg_tsql/src/pltsql.h @@ -31,6 +31,7 @@ #include "utils/plancache.h" #include "utils/portal.h" #include "utils/typcache.h" +#include "tcop/utility.h" #include "dynavec.h" #include "dynastack.h" @@ -47,16 +48,16 @@ #undef _ #define _(x) dgettext(TEXTDOMAIN, x) -#define PLTSQL_INSTR_ENABLED() \ - (pltsql_instr_plugin_ptr && (*pltsql_instr_plugin_ptr) && \ - (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_metric) +#define PLTSQL_INSTR_ENABLED() \ + (pltsql_instr_plugin_ptr && (*pltsql_instr_plugin_ptr) && \ + (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_metric) -#define TSQLInstrumentation(metric) \ -({ if ((pltsql_instr_plugin_ptr && (*pltsql_instr_plugin_ptr) && (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_metric)) \ - (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_metric(metric); \ +#define TSQLInstrumentation(metric) \ +({ if ((pltsql_instr_plugin_ptr && (*pltsql_instr_plugin_ptr) && (*pltsql_instr_plugin_ptr)->pltsql_instr_increment_metric)) \ + (*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 +78,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; @@ -115,6 +116,12 @@ typedef enum PLtsql_promise_type PLTSQL_PROMISE_TG_TAG } PLtsql_promise_type; + +typedef enum PLtsql_dbcc_stmt_type +{ + PLTSQL_DBCC_CHECKIDENT +} PLtsql_dbcc_stmt_type; + /* * Variants distinguished in PLtsql_type structs */ @@ -134,34 +141,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 +180,22 @@ 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 + PLTSQL_STMT_KILL, + /* 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_CHANGE_DBOWNER, + PLTSQL_STMT_DBCC, + PLTSQL_STMT_GRANTSCHEMA, + PLTSQL_STMT_FULLTEXTINDEX, } PLtsql_stmt_type; /* @@ -251,7 +263,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 +279,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 +323,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 +336,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; /* @@ -387,6 +402,9 @@ typedef struct PLtsql_var int cursor_explicit_argrow; int cursor_options; + /* to identify if variable is getting used for babelfish GUC */ + bool is_babelfish_guc; + /* Fields below here can change at runtime */ Datum value; @@ -488,14 +506,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 +724,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,18 +933,46 @@ 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; +/* + * DBCC statement type + */ +typedef union PLtsql_dbcc_stmt_data +{ + struct dbcc_checkident + { + char *db_name; + char *schema_name; + char *table_name; + bool is_reseed; + char *new_reseed_value; + bool no_infomsgs; + } dbcc_checkident; + +} PLtsql_dbcc_stmt_data; + +/* + * DBCC statement + */ +typedef struct PLtsql_stmt_dbcc +{ + PLtsql_stmt_type cmd_type; + int lineno; + PLtsql_dbcc_stmt_type dbcc_stmt_type; + PLtsql_dbcc_stmt_data dbcc_stmt_data; +} PLtsql_stmt_dbcc; + /* * RETURN statement */ @@ -956,7 +1002,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,12 +1035,51 @@ 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; +/* + * ALTER AUTHORIZATION ON DATABASE:: TO + */ +typedef struct PLtsql_stmt_change_dbowner +{ + PLtsql_stmt_type cmd_type; + int lineno; + char *db_name; + char *new_owner_name; /* Login name for new owner */ +} PLtsql_stmt_change_dbowner; + +/* + * Grant on schema stmt + */ +typedef struct PLtsql_stmt_grantschema +{ + PLtsql_stmt_type cmd_type; + int lineno; + bool is_grant; + List *privileges; /* list of privileges */ + List *grantees; /* list of users */ + bool with_grant_option; + char *schema_name; /* schema name */ +} PLtsql_stmt_grantschema; + +/* + * Fulltext Index stmt + */ +typedef struct PLtsql_stmt_fulltextindex +{ + PLtsql_stmt_type cmd_type; + int lineno; + char *table_name; /* table name */ + List *column_name; /* column name */ + char *index_name; /* index name */ + char *schema_name; /* schema name */ + bool is_create; /* flag for create index */ +} PLtsql_stmt_fulltextindex; + /* * ASSERT statement */ @@ -1008,9 +1093,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 +1110,26 @@ 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? */ + bool is_set_tran_isolation; /* SET TRANSACTION ISOLATION? */ + char *original_query; /* Only for batch level statement. */ } PLtsql_stmt_execsql; /* @@ -1052,11 +1140,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 +1154,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 +1166,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 +1218,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 +1262,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 +1290,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 +1312,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 +1328,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 +1344,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 +1353,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 +1362,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; - - MemoryContext stmt_mcontext; + PLtsql_estate_err *save_cur_error; - bool partial_restored; /* set true before executing catch block */ + MemoryContext stmt_mcontext; + + 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 +1411,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 +1472,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 +1489,18 @@ 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; + + int pivot_number; + List *pivot_parsetree_list; - 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 +1553,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,140 +1611,143 @@ 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); + uint32_t (*get_client_pid) (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); 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; @@ -1658,11 +1758,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; /* @@ -1699,21 +1799,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; @@ -1726,7 +1826,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 @@ -1754,29 +1854,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 @@ -1796,12 +1896,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; @@ -1810,8 +1910,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; /********************************************************************** @@ -1822,37 +1922,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); @@ -1868,29 +1968,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); /* @@ -1898,15 +1999,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); /* @@ -1928,11 +2029,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(); @@ -1947,20 +2048,31 @@ 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 List *gen_grantschema_subcmds(const char *schema, const char *db_user, bool is_grant, bool with_grant_option, const char *privilege); +extern char *gen_createfulltextindex_cmds(const char *table_name, const char *schema_name, const List *column_name, const char *index_name); +extern char *gen_dropfulltextindex_cmds(const char *index_name, const char *schema_name); +extern char *get_fulltext_index_name(Oid relid, const char *table_name); +extern const char *gen_schema_name_for_fulltext_index(const char *schema_name); +extern bool check_fulltext_exist(const char *schema_name, const char *table_name); +extern bool is_unique_index(Oid relid, const char *index_name); +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); +void PLTsqlProcessTransaction(Node *parsetree, + ParamListInfo params, + QueryCompletion *qc); + extern void PLTsqlStartTransaction(char *txnName); extern void PLTsqlCommitTransaction(QueryCompletion *qc, bool chain); @@ -1981,37 +2093,43 @@ extern void update_DropOwnedStmt(Node *n, List *role_list); extern void update_DropRoleStmt(Node *n, const char *role); extern void update_DropStmt(Node *n, const char *object); 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_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee, const char *priv); +extern void update_AlterDefaultPrivilegesStmt(Node *n, const char *object, const char *grantee, const char *priv); 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); +extern bool pltsql_createFunction(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, + ParamListInfo params); +extern Oid get_sys_varcharoid(void); +extern Oid get_sysadmin_oid(void); 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); @@ -2025,37 +2143,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., @@ -2078,6 +2197,7 @@ 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); +extern void exec_utility_cmd_helper(char *query_str); #endif /* PLTSQL_H */ diff --git a/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c b/contrib/babelfishpg_tsql/src/pltsql_bulkcopy.c index 752820d698..9384ba5adc 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,25 +102,29 @@ 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; } PG_CATCH(); { + HOLD_INTERRUPTS(); /* 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); + RESUME_INTERRUPTS(); PG_RE_THROW(); } 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 +170,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 +193,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 +236,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 +542,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 +615,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 +634,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,18 +657,29 @@ ExecuteBulkCopy(BulkCopyState cstate, int rowCount, int colCount, } else { - /* 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]; + /* + * In case of reordered list of columns, we get the next index(col_index_to_insert) + * from cstate->attnumlist which points to the original column index in the + * TupleTableSlot. On the other hand we also need to maintain the index + * (col_index_to_fetch) which points to the next column's value in the order as received. + * NOTE: j will never be >= colCount since that is handled by protocol. + */ + int col_index_to_insert = lfirst_int(&cstate->attnumlist->elements[j]) - 1; + int col_index_to_fetch = cur_row_in_batch * colCount + j; + + if (Nulls[col_index_to_fetch]) + myslot->tts_isnull[col_index_to_insert] = Nulls[col_index_to_fetch]; else { - myslot->tts_values[i] = Values[cur_row_in_batch * colCount + j]; + myslot->tts_values[col_index_to_insert] = Values[col_index_to_fetch]; } 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 +688,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 +703,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 +723,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 +791,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 +809,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 +870,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 +920,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 +950,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..5b945cf993 100644 --- a/contrib/babelfishpg_tsql/src/pltsql_coerce.c +++ b/contrib/babelfishpg_tsql/src/pltsql_coerce.c @@ -9,13 +9,14 @@ #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" #include "catalog/pg_type.h" #include "catalog/pg_proc.h" #include "catalog/pg_namespace.h" +#include "collation.h" #include "executor/spi.h" #include "mb/pg_wchar.h" #include "nodes/makefuncs.h" @@ -32,6 +33,7 @@ #include "utils/lsyscache.h" #include "utils/syscache.h" #include "pltsql_instr.h" +#include "parser/parse_target.h" #include @@ -42,90 +44,98 @@ extern find_coercion_pathway_hook_type find_coercion_pathway_hook; extern determine_datatype_precedence_hook_type determine_datatype_precedence_hook; extern func_select_candidate_hook_type func_select_candidate_hook; extern coerce_string_literal_hook_type coerce_string_literal_hook; +extern select_common_type_hook_type select_common_type_hook; +extern select_common_typmod_hook_type select_common_typmod_hook; PG_FUNCTION_INFO_V1(init_tsql_coerce_hash_tab); PG_FUNCTION_INFO_V1(init_tsql_datatype_precedence_hash_tab); +static Oid select_common_type_setop(ParseState *pstate, List *exprs, Node **which_expr); +static Oid select_common_type_for_isnull(ParseState *pstate, List *exprs); + /* 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 +143,17 @@ 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'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "sys", "bit", "smalldatetime_to_bit", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "int2", "smalldatetime_to_int2", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "int4", "smalldatetime_to_int4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "int8", "smalldatetime_to_int8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "float4", "smalldatetime_to_float4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "float8", "smalldatetime_to_float8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "smalldatetime", "pg_catalog", "numeric", "smalldatetime_to_numeric", '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 +161,210 @@ 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'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "sys", "bit", "datetime_to_bit", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "pg_catalog", "int2", "datetime_to_int2", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "pg_catalog", "int4", "datetime_to_int4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "pg_catalog", "int8", "datetime_to_int8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "pg_catalog", "float4", "datetime_to_float4", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "pg_catalog", "float8", "datetime_to_float8", 'i', 'f'}, + {TSQL_CAST_ENTRY, "sys", "datetime", "pg_catalog", "numeric", "datetime_to_numeric", '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 +372,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 +444,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 +460,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 +494,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 +518,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 +712,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 +726,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,26 +739,45 @@ 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, bool candidates_are_opers) { - int i; - Oid *argtypes1 = candidate1->args; - Oid *argtypes2 = candidate2->args; + int i; + Oid *argtypes1 = candidate1->args; + Oid *argtypes2 = candidate2->args; + bool can1_is_sametype = true; + bool can2_is_sametype = true; /* * 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)) return true; + /* Prioritize candidates with same-typed arguments for operators only*/ + if (candidates_are_opers) + { + for (i = 1; i < n; ++i) + { + can1_is_sametype &= argtypes1[i-1] == argtypes1[i]; + can2_is_sametype &= argtypes2[i-1] == argtypes2[i]; + } + + if (can2_is_sametype != can1_is_sametype) + return can1_is_sametype; + } + for (i = 0; i < n; ++i) { if (argtypes1[i] == argtypes2[i]) @@ -734,6 +796,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 +807,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 +842,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 +868,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; + bool candidates_are_opers = false; 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 sys_varcharoid = get_sys_varcharoid(); - /* 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 +894,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,31 +905,37 @@ 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); } new_candidates = run_tsql_best_match_heuristics(nargs, input_typeids, candidates); + candidates_are_opers = SearchSysCacheExists1(OPEROID, new_candidates->oid); for (current_candidate = new_candidates; 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; another_candidate = another_candidate->next) { - if (!tsql_has_func_args_higher_precedence(nargs, input_typeids, current_candidate, another_candidate)) + if (!tsql_has_func_args_higher_precedence(nargs, input_typeids, current_candidate, another_candidate, candidates_are_opers)) { has_highest_precedence = false; break; @@ -875,10 +949,23 @@ 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; } +static bool +is_tsql_char_type_with_len(Oid type) +{ + common_utility_plugin *utilptr = common_utility_plugin_ptr; + return utilptr->is_tsql_bpchar_datatype(type) || + utilptr->is_tsql_nchar_datatype(type) || + utilptr->is_tsql_varchar_datatype(type) || + utilptr->is_tsql_nvarchar_datatype(type); +} + static Node * tsql_coerce_string_literal_hook(ParseCallbackState *pcbstate, Oid targetTypeId, int32 targetTypeMod, int32 baseTypeMod, @@ -886,9 +973,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 +983,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 forbids implicit 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 +1013,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,80 +1035,118 @@ 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); } } + else if ((*common_utility_plugin_ptr->is_tsql_binary_datatype) (baseTypeId) || + (*common_utility_plugin_ptr->is_tsql_varbinary_datatype) (baseTypeId)) + { + /* + * binary datatype should be passed in client encoding + * when explicit cast is called + */ + + TypeName *varcharTypeName = makeTypeNameFromNameList(list_make2(makeString("sys"), + makeString("varchar"))); + Node *result; + Const *tempcon; + + typenameTypeIdAndMod(NULL, (const TypeName *)varcharTypeName, &baseTypeId, &baseTypeMod); + + tempcon = makeConst(varcharTypeName->typeOid, -1, + tsql_get_server_collation_oid_internal(false), + -1, PointerGetDatum(cstring_to_text(value)), + false, false); + + result = coerce_to_target_type(NULL, (Node *) tempcon, baseTypeId, + targetTypeId, targetTypeMod, + COERCION_EXPLICIT, + COERCE_EXPLICIT_CAST, + location); + + pfree(varcharTypeName); + ReleaseSysCache(baseType); + + return result; + } else { newcon->constvalue = stringTypeDatum(baseType, value, inputTypeMod); @@ -1022,21 +1156,198 @@ 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; } +static bool +expr_is_null(Node *expr) +{ + return IsA(expr, Const) && ((Const*)expr)->constisnull + && exprType(expr) == UNKNOWNOID; +} + +static bool +is_tsql_str_const(Node *expr) +{ + return exprType(expr) == UNKNOWNOID && IsA(expr, Const) && !((Const*)expr)->constisnull; +} + +static bool +expr_is_var_max(Node *expr) +{ + common_utility_plugin *utilptr = common_utility_plugin_ptr; + return exprTypmod(expr) == -1 && ( + utilptr->is_tsql_varchar_datatype(exprType(expr)) || + utilptr->is_tsql_nvarchar_datatype(exprType(expr)) || + utilptr->is_tsql_varbinary_datatype(exprType(expr)) || + utilptr->is_tsql_sys_varbinary_datatype(exprType(expr))); +} + +/* + * Handles special cases for finding a type when two or more need to be merged + * Splits handling between cases with setops and values, and for ISNULL + * + * If InvalidOid is returned, pg's select_common_type will attempt to + * find a common type instead. + */ +static Oid +tsql_select_common_type_hook(ParseState *pstate, List *exprs, const char *context, + Node **which_expr) +{ + if (sql_dialect != SQL_DIALECT_TSQL) + return InvalidOid; + + if (!context) + return InvalidOid; + else if (strncmp(context, "ISNULL", strlen("ISNULL")) == 0) + return select_common_type_for_isnull(pstate, exprs); + else if (strncmp(context, "UNION", strlen("UNION")) == 0 || + strncmp(context, "INTERSECT", strlen("INTERSECT")) == 0 || + strncmp(context, "EXCEPT", strlen("EXCEPT")) == 0 || + strncmp(context, "VALUES", strlen("VALUES")) == 0 || + strncmp(context, "UNION/INTERSECT/EXCEPT", strlen("UNION/INTERSECT/EXCEPT")) == 0) + return select_common_type_setop(pstate, exprs, which_expr); + + return InvalidOid; +} + +/* + * When we must merge types together (i.e. UNION), if all types are + * null, literals, or [n][var]char types, then return the correct + * output type based on TSQL's precedence rules + */ +static Oid +select_common_type_setop(ParseState *pstate, List *exprs, Node **which_expr) +{ + Node *result_expr = (Node*) linitial(exprs); + Oid result_type = InvalidOid; + ListCell *lc; + + /* Find a common type based on precedence. NULLs are ignored, and make + * string literals varchars. If a type besides CHAR, NCHAR, VARCHAR, + * or NVARCHAR is present, let engine handle finding the type. */ + foreach(lc, exprs) + { + Node *expr = (Node *) lfirst(lc); + Oid type = exprType(expr); + + if (expr_is_null(expr)) + continue; + else if (is_tsql_str_const(expr)) + type = common_utility_plugin_ptr->lookup_tsql_datatype_oid("varchar"); + else if (!is_tsql_char_type_with_len(type)) + return InvalidOid; + + if (tsql_has_higher_precedence(type, result_type) || result_type == InvalidOid) + { + result_expr = expr; + result_type = type; + } + } + + if (which_expr) + *which_expr = result_expr; + return result_type; +} + +/* + * select_common_type_for_isnull - Deduce common data type for ISNULL(check_expression , replacement_value) + * function. + * This function should return same as check_expression. If that expression is NULL then reyurn the data type of + * replacement_value. If replacement_value is also NULL then return INT. + */ +static Oid +select_common_type_for_isnull(ParseState *pstate, List *exprs) +{ + Node *pexpr; + Oid ptype; + + Assert(exprs != NIL); + pexpr = (Node *) linitial(exprs); + ptype = exprType(pexpr); + + /* Check if first arg (check_expression) is NULL literal */ + if (IsA(pexpr, Const) && ((Const *) pexpr)->constisnull && ptype == UNKNOWNOID) + { + Node *nexpr = (Node *) lfirst(list_second_cell(exprs)); + Oid ntype = exprType(nexpr); + /* Check if second arg (replace_expression) is NULL literal */ + if (IsA(nexpr, Const) && ((Const *) nexpr)->constisnull && ntype == UNKNOWNOID) + { + return INT4OID; + } + /* If second argument is non-null string literal */ + if (ntype == UNKNOWNOID) + { + return get_sys_varcharoid(); + } + return ntype; + } + /* If first argument is non-null string literal */ + if (ptype == UNKNOWNOID) + { + return get_sys_varcharoid(); + } + return ptype; +} + +/* + * When we must merge types together (i.e. UNION), if the target type + * is CHAR, NCHAR, or BINARY, make the typmod (representing the length) + * equal to that of the largest expression + * + * If -1 is returned, engine will handle finding a common typmod as usual + */ +static int32 +tsql_select_common_typmod_hook(ParseState *pstate, List *exprs, Oid common_type) +{ + int32 max_typmods; + ListCell *lc; + common_utility_plugin *utilptr = common_utility_plugin_ptr; + + if (sql_dialect != SQL_DIALECT_TSQL) + return -1; + + if (!is_tsql_char_type_with_len(common_type) && + !utilptr->is_tsql_binary_datatype(common_type) && + !utilptr->is_tsql_sys_binary_datatype(common_type) && + !utilptr->is_tsql_varbinary_datatype(common_type) && + !utilptr->is_tsql_sys_varbinary_datatype(common_type)) + return -1; + + /* If resulting type is a length, need to be max of length types */ + foreach(lc, exprs) + { + Node *expr = (Node*) lfirst(lc); + int32 typmod = exprTypmod(expr); + + if (is_tsql_str_const(expr)) + typmod = strlen(DatumGetCString( ((Const*)expr)->constvalue )) + VARHDRSZ; + + if (expr_is_var_max(expr)) + return -1; + + if (lc == list_head(exprs)) + max_typmods = typmod; + else + max_typmods = Max(max_typmods, typmod); + } + + return max_typmods; +} + 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); @@ -1044,15 +1355,17 @@ init_tsql_datatype_precedence_hash_tab(PG_FUNCTION_ARGS) determine_datatype_precedence_hook = tsql_has_higher_precedence; func_select_candidate_hook = tsql_func_select_candidate; coerce_string_literal_hook = tsql_coerce_string_literal_hook; + select_common_type_hook = tsql_select_common_type_hook; + select_common_typmod_hook = tsql_select_common_typmod_hook; 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 +1382,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 +1393,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,30 +1419,36 @@ 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) +BBF_Pragma_IgnoreFloatConversionWarning_Push +inline static float4 +ftrunc_(float4 arg1) { - float8 result; + float8 result; if (arg1 >= 0) result = floor(arg1); + else result = -floor(-arg1); return result; } +BBF_Pragma_IgnoreFloatConversionWarning_Pop /* dtrunci8(X) = dtoi8(dtrunc(X)) */ PG_FUNCTION_INFO_V1(dtrunci8); @@ -1137,7 +1456,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 +1481,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 +1506,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,14 +1531,16 @@ 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 * on just-out-of-range values that would round into range. Note * assumption that rint() will pass through a NaN or Inf unchanged. */ + BBF_Pragma_IgnoreFloatConversionWarning_Push num = rint(ftrunc_(num)); + BBF_Pragma_IgnoreFloatConversionWarning_Pop /* Range check */ if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT64(num))) @@ -1237,14 +1558,16 @@ 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 * on just-out-of-range values that would round into range. Note * assumption that rint() will pass through a NaN or Inf unchanged. */ + BBF_Pragma_IgnoreFloatConversionWarning_Push num = rint(ftrunc_(num)); + BBF_Pragma_IgnoreFloatConversionWarning_Pop /* Range check */ if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT32(num))) @@ -1262,14 +1585,16 @@ 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 * on just-out-of-range values that would round into range. Note * assumption that rint() will pass through a NaN or Inf unchanged. */ + BBF_Pragma_IgnoreFloatConversionWarning_Push num = rint(ftrunc_(num)); + BBF_Pragma_IgnoreFloatConversionWarning_Pop /* Range check */ if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT16(num))) @@ -1289,9 +1614,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 +1624,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } @@ -1330,6 +1656,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 +1666,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 +1678,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 +1694,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_NAME(n); } @@ -1399,6 +1726,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 d7e20d921d..5e3c05622e 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, @@ -182,6 +183,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_VARYING, INSTR_UNSUPPORTED_TSQL_UNKNOWN_DDL, INSTR_UNSUPPORTED_TSQL_NOT_IMPLEMENTED_SYSTEM_PROCEDURE, + INSTR_UNSUPPORTED_TSQL_ALTER_AUTHORIZATION, INSTR_TSQL_TIMESTAMP_DATATYPE, INSTR_TSQL_ROWVERSION_DATATYPE, INSTR_TSQL_HIERARCHYID_DATATYPE, @@ -247,7 +249,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, @@ -496,7 +497,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_TSQL_BINARYFLOAT4, INSTR_TSQL_BINARYFLOAT8, INSTR_TSQL_VARBINARY_COMPARE, - + INSTR_TSQL_SMALLDATETIMEIN, INSTR_TSQL_TIME2SMALLDATETIME, INSTR_TSQL_DATE2SMALLDATETIME, @@ -605,7 +606,7 @@ typedef enum PgTsqlInstrMetricType { INSTR_UNSUPPORTED_TSQL_PROCID, INSTR_TSQL_VERSION, INSTR_TSQL_SERVERNAME, - + INSTR_UNSUPPORTED_TSQL_OPTION_ROWCOUNT, INSTR_TSQL_FETCH_STATUS, @@ -632,13 +633,15 @@ typedef enum PgTsqlInstrMetricType { INSTR_TSQL_ISOLATION_LEVEL_READ_UNCOMMITTED, INSTR_TSQL_ISOLATION_LEVEL_READ_COMMITTED, + INSTR_TSQL_ISOLATION_LEVEL_REPEATABLE_READ, INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_REPEATABLE_READ, INSTR_TSQL_ISOLATION_LEVEL_SNAPSHOT, + INSTR_TSQL_ISOLATION_LEVEL_SERIALIZABLE, INSTR_UNSUPPORTED_TSQL_ISOLATION_LEVEL_SERIALIZABLE, 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 dc80e0b768..df3c57df71 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" @@ -22,19 +22,37 @@ #include "access/table.h" #include "access/genam.h" #include "catalog.h" +#include "parser/gramparse.h" +#include "hooks.h" +#include "tcop/utility.h" #include "multidb.h" 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); -/* +bool +pltsql_createFunction(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, + ParamListInfo params); + +extern bool restore_tsql_tabletype; +extern char *get_cur_db_name(void); +extern char *construct_unique_index_name(char *index_name, char *relation_name); +extern char *get_physical_schema_name(char *db_name, const char *schema_name); +extern const char *get_dbo_schema_name(const char *dbname); + +/* To cache oid of sys.varchar */ +static Oid sys_varcharoid = InvalidOid; +static Oid sysadmin_oid = InvalidOid; + +/* * 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 @@ -49,6 +67,279 @@ const uint64 PLTSQL_LOCKTAG_OFFSET = 0xABCDEF; (uint32) ((((int64) key16) + PLTSQL_LOCKTAG_OFFSET) >> 32), \ (uint32) (((int64) key16) + PLTSQL_LOCKTAG_OFFSET), \ 3) +/* + * Transaction processing using tsql semantics + */ +void +PLTsqlProcessTransaction(Node *parsetree, + ParamListInfo params, + QueryCompletion *qc) +{ + char *txnName = NULL; + TransactionStmt *stmt = (TransactionStmt *) parsetree; + + if (params != NULL && params->numParams > 0 && !params->params[0].isnull) + { + Oid typOutput; + bool typIsVarlena; + FmgrInfo finfo; + + Assert(params->numParams == 1); + getTypeOutputInfo(params->params[0].ptype, &typOutput, &typIsVarlena); + fmgr_info(typOutput, &finfo); + txnName = OutputFunctionCall(&finfo, params->params[0].value); + } + else + txnName = stmt->savepoint_name; + + if (txnName != NULL && strlen(txnName) > TSQL_TXN_NAME_LIMIT / 2) + ereport(ERROR, + (errcode(ERRCODE_NAME_TOO_LONG), + errmsg("Transaction name length %zu above limit %u", + strlen(txnName), TSQL_TXN_NAME_LIMIT / 2))); + + if (AbortCurTransaction) + { + if (stmt->kind == TRANS_STMT_BEGIN || + stmt->kind == TRANS_STMT_COMMIT || + stmt->kind == TRANS_STMT_SAVEPOINT) + 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."))); + } + + switch (stmt->kind) + { + case TRANS_STMT_BEGIN: + { + PLTsqlStartTransaction(txnName); + } + break; + + case TRANS_STMT_COMMIT: + { + if (exec_state_call_stack && + exec_state_call_stack->estate && + exec_state_call_stack->estate->insert_exec && + NestedTranCount <= 1) + ereport(ERROR, + (errcode(ERRCODE_TRANSACTION_ROLLBACK), + errmsg("Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first."))); + + PLTsqlCommitTransaction(qc, stmt->chain); + } + break; + + case TRANS_STMT_ROLLBACK: + { + if (exec_state_call_stack && + exec_state_call_stack->estate && + exec_state_call_stack->estate->insert_exec) + ereport(ERROR, + (errcode(ERRCODE_TRANSACTION_ROLLBACK), + errmsg("Cannot use the ROLLBACK statement within an INSERT-EXEC statement."))); + PLTsqlRollbackTransaction(txnName, qc, stmt->chain); + } + break; + + case TRANS_STMT_SAVEPOINT: + RequireTransactionBlock(true, "SAVEPOINT"); + DefineSavepoint(txnName); + break; + + default: + ereport(ERROR, + (errcode(ERRCODE_INVALID_TRANSACTION_INITIATION), + errmsg("Unsupported transaction command : %d", stmt->kind))); + break; + } +} + + +bool +pltsql_createFunction(ParseState *pstate, PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, + ParamListInfo params) +{ + Node *parsetree = pstmt->utilityStmt; + CreateFunctionStmt *stmt = (CreateFunctionStmt *)parsetree; + ListCell *option, *location_cell = NULL; + DefElem *language_item = NULL; + char *language = NULL; + ObjectAddress address; + bool isCompleteQuery = (context != PROCESS_UTILITY_SUBCOMMAND); + bool needCleanup; + Node *tbltypStmt = NULL; + Node *trigStmt = NULL; + ObjectAddress tbltyp; + int origname_location = -1; + + pstate->p_sourcetext = queryString; + + foreach(option, stmt->options) + { + DefElem *defel = (DefElem *)lfirst(option); + + if (strcmp(defel->defname, "language") == 0) + { + if (language_item) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"), + parser_errposition(pstate, defel->location))); + language_item = defel; + } + } + + if (language_item) + language = strVal(language_item->arg); + + if(!((language && !strcmp(language,"pltsql")) || sql_dialect == SQL_DIALECT_TSQL)) + { + return false; + } + else + { + /* 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(); + { + if (isCompleteQuery) + EventTriggerDDLCommandStart(parsetree); + + foreach (option, stmt->options) + { + 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 = defel->arg; + } + else if (strcmp(defel->defname, "trigStmt") == 0) + { + /* + * trigStmt is an implicit option in tsql dialect, + * we use this mechanism to create tsql style function + * and trigger in one statement. + */ + trigStmt = defel->arg; + } + else if (strcmp(defel->defname, "location") == 0) + { + /* + * 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. + */ + origname_location = intVal((Node *)defel->arg); + location_cell = option; + pfree(defel); + } + } + + /* 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); + + /* + * For tbltypStmt, we need to first process the CreateStmt + * to create the type that will be used as the function's + * return type. Then, after the function is created, add a + * dependency between the type and the function. + */ + if (tbltypStmt) + { + /* Handle tbltypStmt, which is a CreateStmt */ + PlannedStmt *wrapper; + + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = tbltypStmt; + wrapper->stmt_location = pstmt->stmt_location; + wrapper->stmt_len = pstmt->stmt_len; + + ProcessUtility(wrapper, + queryString, + false, + PROCESS_UTILITY_SUBCOMMAND, + params, + NULL, + None_Receiver, + NULL); + + /* Need CCI between commands */ + CommandCounterIncrement(); + } + + address = CreateFunction(pstate, stmt); + + /* Store function/procedure related metadata in babelfish catalog */ + pltsql_store_func_default_positions(address, stmt->parameters, queryString, origname_location); + + if (tbltypStmt || restore_tsql_tabletype) + { + /* + * Add internal dependency between the table type and + * the function. + */ + tbltyp.classId = TypeRelationId; + tbltyp.objectId = typenameTypeId(pstate, + 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 + * dependency so that Drop Trigger CASCADE will drop the + * implicit trigger function. + * Create trigger takes care of dependency addition. + */ + if (trigStmt) + { + (void)CreateTrigger((CreateTrigStmt *)trigStmt, + 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. + */ + EventTriggerCollectSimpleCommand(address, InvalidObjectAddress, + parsetree); + + if (isCompleteQuery) + { + EventTriggerSQLDrop(parsetree); + EventTriggerDDLCommandEnd(parsetree); + } + } + + PG_CATCH(); + { + if (needCleanup) + EventTriggerEndCompleteQuery(); + PG_RE_THROW(); + } + PG_END_TRY(); + + if (needCleanup) + EventTriggerEndCompleteQuery(); + + return true; + } +} /* * Setup default typmod for sys types/domains when typmod isn't specified @@ -66,8 +357,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 +370,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 +380,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 +391,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 +409,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 +422,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 +434,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 +463,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 +481,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 +505,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 +519,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 +545,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 +560,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 +594,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 +603,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 +651,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 +707,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 +718,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 +742,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 +766,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 +820,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 +842,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 +863,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 +881,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 +894,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 +915,7 @@ void update_AlterRoleStmt(Node *n, RoleSpec *role) { AlterRoleStmt *stmt = (AlterRoleStmt *) n; + if (!IsA(stmt, AlterRoleStmt)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), @@ -617,6 +928,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 +942,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,22 +968,21 @@ 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)); - pfree(tmp); - if (!stmt->roles) return; @@ -684,7 +995,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 +1008,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"))); @@ -704,9 +1017,10 @@ update_GrantRoleStmt(Node *n, List *privs, List *roles) } void -update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee) +update_GrantStmt(Node *n, const char *object, const char *obj_schema, const char *grantee, const char *priv) { - 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,21 +1028,57 @@ 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); } + + if (priv && stmt->privileges) + { + AccessPriv *tmp = (AccessPriv *) llast(stmt->privileges); + + tmp->priv_name = pstrdup(priv); + } +} + +void +update_AlterDefaultPrivilegesStmt(Node *n, const char *object, const char *grantee, const char *priv) +{ + AlterDefaultPrivilegesStmt *stmt = (AlterDefaultPrivilegesStmt *) n; + + ListCell *lc; + + if (!IsA(stmt, AlterDefaultPrivilegesStmt)) + ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("query is not a AlterDefaultPrivilegesStmt"))); + + if (grantee && priv && stmt->action) + { + update_GrantStmt((Node *)(stmt->action), NULL, NULL, grantee, priv); + } + + foreach(lc, stmt->options) + { + if (object) + { + DefElem *tmp = (DefElem *) lfirst(lc); + tmp->defname = pstrdup("schemas"); + tmp->arg = (Node *)list_make1(makeString((char *)object)); + } + } } 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 +1089,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 +1098,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 +1121,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 +1134,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 +1151,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 +1168,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 +1194,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 +1203,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 +1213,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); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); appendStringInfo(&argbuf, "%s(", funcname); for (i = 0; i < nargs; i++) @@ -874,8 +1233,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); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); } PG_END_TRY(); @@ -890,23 +1249,24 @@ 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)) - 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), - form_proctup->pronargs, - form_proctup->proargtypes.values); + 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 -report_info_or_warning(int elevel, char* message) +report_info_or_warning(int elevel, char *message) { ereport(elevel, errmsg("%s", message)); @@ -914,19 +1274,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 +1302,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 +1353,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 +1400,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 +1417,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 +1427,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 +1449,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 +1479,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 +1505,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 +1521,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 +1539,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 +1553,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 +1566,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 +1584,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 +1598,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 +1621,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 +1629,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,9 +1651,348 @@ 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); table_close(tgrel, AccessShareLock); return tgrelid; } + +/* + * Helper function to execute a utility command using + * ProcessUtility(). Caller should make sure their + * inputs are sanitized to prevent unexpected behaviour. + */ +void +exec_utility_cmd_helper(char *query_str) +{ + List *parsetree_list; + Node *stmt; + PlannedStmt *wrapper; + + parsetree_list = raw_parser(query_str, RAW_PARSE_DEFAULT); + + if (list_length(parsetree_list) != 1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", + list_length(parsetree_list)))); + + /* Update the dummy statement with real values */ + stmt = parsetree_nth_stmt(parsetree_list, 0); + + /* Run the built query */ + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = strlen(query_str); + + /* do this step */ + ProcessUtility(wrapper, + query_str, + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); +} + +Oid get_sys_varcharoid(void) +{ + Oid sys_oid; + if (OidIsValid(sys_varcharoid)) + { + return sys_varcharoid; + } + sys_oid = get_namespace_oid("sys", false); + sys_varcharoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum("varchar"), ObjectIdGetDatum(sys_oid)); + if (!OidIsValid(sys_varcharoid)) + { + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Oid corresponding to sys.varchar datatype could not be found."))); + } + return sys_varcharoid; +} + +Oid get_sysadmin_oid(void) +{ + if (!OidIsValid(sysadmin_oid)) + sysadmin_oid = get_role_oid("sysadmin", true); + + return sysadmin_oid; +} + +List +*gen_grantschema_subcmds(const char *schema, const char *rolname, bool is_grant, bool with_grant_option, const char *privilege) +{ + StringInfoData query; + List *stmt_list; + Node *stmt; + int expected_stmts = 2; + int i = 0; + initStringInfo(&query); + if (is_grant) + { + if (strcmp(privilege, "execute") == 0) + { + if (with_grant_option) + { + appendStringInfo(&query, "GRANT dummy ON ALL FUNCTIONS IN SCHEMA dummy TO dummy WITH GRANT OPTION; "); + appendStringInfo(&query, "GRANT dummy ON ALL PROCEDURES IN SCHEMA dummy TO dummy WITH GRANT OPTION; "); + } + else + { + appendStringInfo(&query, "GRANT dummy ON ALL FUNCTIONS IN SCHEMA dummy TO dummy; "); + appendStringInfo(&query, "GRANT dummy ON ALL PROCEDURES IN SCHEMA dummy TO dummy; "); + } + } + else + { + if (with_grant_option) + appendStringInfo(&query, "GRANT dummy ON ALL TABLES IN SCHEMA dummy TO dummy WITH GRANT OPTION; "); + else + appendStringInfo(&query, "GRANT dummy ON ALL TABLES IN SCHEMA dummy TO dummy; "); + appendStringInfo(&query, "ALTER DEFAULT PRIVILEGES IN SCHEMA dummy GRANT dummy ON TABLES TO dummy; "); + } + } + else + { + if (strcmp(privilege, "execute") == 0) + { + appendStringInfo(&query, "REVOKE dummy ON ALL FUNCTIONS IN SCHEMA dummy FROM dummy; "); + appendStringInfo(&query, "REVOKE dummy ON ALL PROCEDURES IN SCHEMA dummy FROM dummy; "); + } + else + { + appendStringInfo(&query, "REVOKE dummy ON ALL TABLES IN SCHEMA dummy FROM dummy; "); + appendStringInfo(&query, "ALTER DEFAULT PRIVILEGES IN SCHEMA dummy REVOKE dummy ON TABLES FROM dummy; "); + } + } + stmt_list = raw_parser(query.data, RAW_PARSE_DEFAULT); + if (list_length(stmt_list) != expected_stmts) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected %d statements, but got %d statements after parsing", + expected_stmts, list_length(stmt_list)))); + /* Replace dummy elements in parsetree with real values */ + stmt = parsetree_nth_stmt(stmt_list, i++); + update_GrantStmt(stmt, schema, NULL, rolname, privilege); + + stmt = parsetree_nth_stmt(stmt_list, i++); + if (strcmp(privilege, "execute") == 0) + update_GrantStmt(stmt, schema, NULL, rolname, privilege); + else + update_AlterDefaultPrivilegesStmt(stmt, schema, rolname, privilege); + + return stmt_list; +} + +/* + * Generates the schema name for fulltext index statements + * depending on whether it's master schema or not + */ +const char * +gen_schema_name_for_fulltext_index(const char *schema_name) +{ + char *dbname = get_cur_db_name(); + if (strlen(schema_name) == 0) + return get_dbo_schema_name(dbname); + else + return get_physical_schema_name(dbname, schema_name); +} + +/* + * check_fulltext_exist + * Check if the fulltext index exist for the given table and schema + * during execution of CONTAINS() statement + */ +bool +check_fulltext_exist(const char *schema_name, const char *table_name) +{ + const char *gen_schema_name = gen_schema_name_for_fulltext_index((char *)schema_name); + char *ft_index_name; + Oid schemaOid; + Oid relid; + + schemaOid = LookupExplicitNamespace(gen_schema_name, true); + + // Check if schema exists + if (!OidIsValid(schemaOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + schema_name))); + + relid = get_relname_relid((const char *) table_name, schemaOid); + + + // Check if table exists + if (!OidIsValid(relid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", + table_name))); + + ft_index_name = get_fulltext_index_name(relid, table_name); + return ft_index_name != NULL; +} + +/* + * get_fulltext_index_name + * Get the fulltext index name of a relation specified by OID + */ +char +*get_fulltext_index_name(Oid relid, const char *table_name) +{ + Relation relation = RelationIdGetRelation(relid); + List *indexoidlist = RelationGetIndexList(relation); + ListCell *cell; + char *ft_index_name = NULL; + char *table_name_cpy = palloc(strlen(table_name) + 1); + char *temp_ft_index_name; + + strcpy(table_name_cpy, table_name); + temp_ft_index_name = construct_unique_index_name("ft_index", table_name_cpy); + foreach(cell, indexoidlist) + { + Oid indexOid = lfirst_oid(cell); + ft_index_name = get_rel_name(indexOid); + + if (strcmp(ft_index_name, temp_ft_index_name) == 0) + break; + + ft_index_name = NULL; + } + + RelationClose(relation); + list_free(indexoidlist); + pfree(table_name_cpy); + return ft_index_name; +} + +/* + * is_unique_index + * Check if given index is unique index of a relation specified by OID + */ +bool +is_unique_index(Oid relid, const char *index_name) +{ + Relation relation = RelationIdGetRelation(relid); + List *indexoidlist = RelationGetIndexList(relation); + ListCell *cell; + bool is_unique = false; + int unique_key_count = 0; + + foreach(cell, indexoidlist) + { + Oid indexOid = lfirst_oid(cell); + char *name = get_rel_name(indexOid); + + if (strcmp(name, index_name) == 0) + { + HeapTuple indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexOid)); + Form_pg_index indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + + /* Check if the key column is unique and is of single-key */ + if (indexForm->indisunique && indexForm->indrelid == relid && indexForm->indnkeyatts == 1) + { + /* Check if the key column is non-nullable */ + for (int i = 0; i < indexForm->indnatts; i++) + { + AttrNumber attnum = indexForm->indkey.values[i]; + if (attnum != 0) + { + HeapTuple attTuple = SearchSysCache2(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum)); + if(HeapTupleIsValid(attTuple)) + { + Form_pg_attribute attForm = (Form_pg_attribute) GETSTRUCT(attTuple); + + if (attForm->attnotnull) + { + unique_key_count++; + if (unique_key_count > 1) + break; + } + } + ReleaseSysCache(attTuple); + } + } + + if (unique_key_count == 1) + is_unique = true; + } + + ReleaseSysCache(indexTuple); + break; + } + } + + RelationClose(relation); + list_free(indexoidlist); + return is_unique; +} + +char +*gen_createfulltextindex_cmds(const char *table_name, const char *schema_name, const List *column_name, const char *index_name) +{ + StringInfoData query; + + initStringInfo(&query); + + /* + * We prepare the following query to create a fulltext index. + * + * CREATE INDEX ON + * USING gin(to_tsvector('fts_contains_simple', )); + * + */ + appendStringInfo(&query, "CREATE INDEX \"%s\" ON ", index_name); + if (schema_name == NULL || strlen(schema_name) == 0 || *schema_name == '\0') + appendStringInfo(&query, "\"%s\"", table_name); + else + appendStringInfo(&query, "\"%s\".\"%s\"", schema_name, table_name); + + appendStringInfo(&query, "USING GIN("); + for (int i = 0; i < list_length(column_name); i++) + { + char *col_name = (char *) list_nth(column_name, i); + // Add column name + appendStringInfo(&query, "to_tsvector('fts_contains_simple', \"%s\")", col_name); + if (i != list_length(column_name) - 1) + appendStringInfo(&query, ", "); + } + appendStringInfo(&query, ")"); + + return query.data; +} + +char +*gen_dropfulltextindex_cmds(const char *index_name, const char *schema_name) +{ + StringInfoData query; + initStringInfo(&query); + /* + * We prepare the following query to drop a fulltext index. + * + * DROP INDEX + * + */ + appendStringInfo(&query, "DROP INDEX "); + + if (schema_name == NULL || strlen(schema_name) == 0 || *schema_name == '\0') + appendStringInfo(&query, "\"%s\"", index_name); + else + appendStringInfo(&query, "\"%s\".\"%s\"", schema_name, index_name); + return query.data; +} 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 8fe03bb818..32becc556e 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 * *------------------------------------------------------------------------- */ @@ -11,13 +11,18 @@ #include "access/tupdesc.h" #include "access/printtup.h" #include "access/relation.h" +#include "access/table.h" #include "access/xact.h" +#include "access/heapam.h" #include "catalog/pg_type.h" #include "catalog/pg_proc.h" +#include "catalog/pg_foreign_server.h" +#include "catalog/indexing.h" #include "commands/defrem.h" #include "commands/prepare.h" #include "common/string.h" #include "executor/spi.h" +#include "foreign/foreign.h" #include "fmgr.h" #include "funcapi.h" #include "hooks.h" @@ -29,22 +34,27 @@ #include "utils/guc.h" #include "utils/rel.h" #include "utils/syscache.h" +#include "utils/fmgroids.h" +#include "utils/formatting.h" #include "pltsql_instr.h" +#include "pltsql.h" #include "parser/parser.h" #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" #include "tsearch/ts_locale.h" #include "catalog.h" +#include "extendedproperty.h" #include "multidb.h" #include "pltsql.h" #include "session.h" #include "pltsql.h" +#include "rolecmds.h" PG_FUNCTION_INFO_V1(sp_unprepare); PG_FUNCTION_INFO_V1(sp_prepare); @@ -63,69 +73,84 @@ PG_FUNCTION_INFO_V1(sp_addlinkedserver_internal); PG_FUNCTION_INFO_V1(sp_addlinkedsrvlogin_internal); PG_FUNCTION_INFO_V1(sp_droplinkedsrvlogin_internal); PG_FUNCTION_INFO_V1(sp_dropserver_internal); +PG_FUNCTION_INFO_V1(sp_serveroption_internal); PG_FUNCTION_INFO_V1(sp_babelfish_volatility); PG_FUNCTION_INFO_V1(sp_rename_internal); +PG_FUNCTION_INFO_V1(sp_execute_postgresql); +PG_FUNCTION_INFO_V1(sp_enum_oledb_providers_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); 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 void exec_utility_cmd_helper(char *query_str); +static List *gen_sp_rename_subcmds(const char *objname, const char *newname, const char *schemaname, ObjectType objtype, const char *curr_relname); +static void update_bbf_server_options(char *servername, char *optname, char *optvalue, bool isInsert); +static void clean_up_bbf_server_option(char *servername); +static void remove_delimited_identifer(char *str); +static void rename_extended_property(ObjectType objtype, + const char *var_schema_name, + const char *var_major_name, + const char *old_name, const char *new_name); + +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; +/* server options and their default values for babelfish_server_options catalog insert */ +char * srvOptions_optname[BBF_SERVERS_DEF_NUM_COLS - 1] = {"query timeout", "connect timeout"}; +char * srvOptions_optvalue[BBF_SERVERS_DEF_NUM_COLS - 1] = {"0", "0"}; 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", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, @@ -136,20 +161,21 @@ 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(); { set_config_option("babelfishpg_tsql.sql_dialect", old_dialect, - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, @@ -160,7 +186,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, @@ -171,34 +197,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); - result = (HeapTupleHeader) palloc(tuple->t_len); - memcpy(result, tuple->t_data, 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); } 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 +235,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 +268,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 +286,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 +296,111 @@ 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; + + /* The Oid of the table */ + Oid reloid; } 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 = sys.db_id() " + "AND t1.dtd_identifier::int = t3.\"ORDINAL_POSITION\";", viewName); } /* @@ -378,27 +411,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 +447,55 @@ 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; + { + PLtsql_expr *sqlstmt = ((PLtsql_stmt_execsql *) lsecond(pltsql_parse_result->body))->sqlstmt; + if (sqlstmt) + parsedbatch = 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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + 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); + GUC_CONTEXT_CONFIG, + 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. */ @@ -460,13 +512,18 @@ sp_describe_first_result_set_internal(PG_FUNCTION_ARGS) PG_CATCH(); { query = psprintf("DROP VIEW %s", sp_describe_first_result_set_view_name); + HOLD_INTERRUPTS(); if ((rc = SPI_execute(query, false, 1)) < 0) + { + RESUME_INTERRUPTS(); elog(ERROR, "SPI_execute failed: %s", SPI_result_code_string(rc)); + } pfree(query); pfree(sp_describe_first_result_set_view_name); SPI_finish(); + RESUME_INTERRUPTS(); PG_RE_THROW(); } PG_END_TRY(); @@ -479,27 +536,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 +582,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 +609,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 +622,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 +650,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 +717,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 +746,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 +828,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 +854,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 +921,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 +980,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 +1020,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 +1036,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 +1057,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 +1072,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 +1093,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 +1107,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; } @@ -1039,6 +1117,7 @@ sp_describe_undeclared_parameters_internal(PG_FUNCTION_ARGS) strncpy(undeclaredparams->tablename, relation->relname, NAMEDATALEN); undeclaredparams->tablename[relname_len] = '\0'; undeclaredparams->schemaoid = RelationGetNamespace(r); + undeclaredparams->reloid = RelationGetRelid(r); undeclaredparams->targetattnums = (int *) palloc(sizeof(int) * list_length(target_attnums)); undeclaredparams->targetcolnames = (char **) palloc(sizeof(char *) * list_length(target_attnums)); @@ -1047,14 +1126,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 +1146,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 +1170,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 +1221,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 +1236,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 +1256,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,146 +1280,313 @@ 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 " - "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 " - "WHEN T2.name COLLATE sys.database_default = \'char\' THEN 175 " - "WHEN T2.name COLLATE sys.database_default = \'date\' THEN 40 " - "WHEN T2.name COLLATE sys.database_default = \'datetime\' THEN 61 " - "WHEN T2.name COLLATE sys.database_default = \'datetime2\' THEN 42 " - "WHEN T2.name COLLATE sys.database_default = \'datetimeoffset\' THEN 43 " - "WHEN T2.name COLLATE sys.database_default = \'decimal\' THEN 106 " - "WHEN T2.name COLLATE sys.database_default = \'float\' THEN 62 " - "WHEN T2.name COLLATE sys.database_default = \'image\' THEN 34 " - "WHEN T2.name COLLATE sys.database_default = \'int\' THEN 56 " - "WHEN T2.name COLLATE sys.database_default = \'money\' THEN 60 " - "WHEN T2.name COLLATE sys.database_default = \'nchar\' THEN 239 " - "WHEN T2.name COLLATE sys.database_default = \'ntext\' THEN 99 " - "WHEN T2.name COLLATE sys.database_default = \'numeric\' THEN 108 " - "WHEN T2.name COLLATE sys.database_default = \'nvarchar\' THEN 231 " - "WHEN T2.name COLLATE sys.database_default = \'real\' THEN 59 " - "WHEN T2.name COLLATE sys.database_default = \'smalldatetime\' THEN 58 " - "WHEN T2.name COLLATE sys.database_default = \'smallint\' THEN 52 " - "WHEN T2.name COLLATE sys.database_default = \'smallmoney\' THEN 122 " - "WHEN T2.name COLLATE sys.database_default = \'text\' THEN 35 " - "WHEN T2.name COLLATE sys.database_default = \'time\' THEN 41 " - "WHEN T2.name COLLATE sys.database_default = \'tinyint\' THEN 48 " - "WHEN T2.name COLLATE sys.database_default = \'uniqueidentifier\' THEN 36 " - "WHEN T2.name COLLATE sys.database_default = \'varbinary\' THEN 165 " - "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 " - "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) ) + \')\' " - "WHEN T2.name COLLATE sys.database_default = \'nchar\' THEN \'nchar(\' + CAST( C.max_length/2 AS sys.VARCHAR(10) ) + \')\' " - "WHEN T2.name COLLATE sys.database_default = \'binary\' THEN \'binary(\' + CAST( C.max_length AS sys.VARCHAR(10) ) + \')\' " - "WHEN T2.name COLLATE sys.database_default = \'datetime2\' THEN \'datetime2(\' + CAST( C.scale AS sys.VARCHAR(10) ) + \')\' " - "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) ) + \')\' " + 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 T2.name COLLATE sys.database_default " + "WHEN \'bigint\' THEN 127 " + "WHEN \'binary\' THEN 173 " + "WHEN \'bit\' THEN 104 " + "WHEN \'char\' THEN 175 " + "WHEN \'date\' THEN 40 " + "WHEN \'datetime\' THEN 61 " + "WHEN \'datetime2\' THEN 42 " + "WHEN \'datetimeoffset\' THEN 43 " + "WHEN \'decimal\' THEN 106 " + "WHEN \'float\' THEN 62 " + "WHEN \'image\' THEN 34 " + "WHEN \'int\' THEN 56 " + "WHEN \'money\' THEN 60 " + "WHEN \'nchar\' THEN 239 " + "WHEN \'ntext\' THEN 99 " + "WHEN \'numeric\' THEN 108 " + "WHEN \'nvarchar\' THEN 231 " + "WHEN \'real\' THEN 59 " + "WHEN \'smalldatetime\' THEN 58 " + "WHEN \'smallint\' THEN 52 " + "WHEN \'smallmoney\' THEN 122 " + "WHEN \'text\' THEN 35 " + "WHEN \'time\' THEN 41 " + "WHEN \'tinyint\' THEN 48 " + "WHEN \'uniqueidentifier\' THEN 36 " + "WHEN \'varbinary\' THEN 165 " + "WHEN \'varchar\' THEN 167 " + "WHEN \'xml\' THEN 241 " + "ELSE CASE " + "WHEN t.typbasetype = 0 THEN " + "CAST(a.atttypid AS int) " + "ELSE " + "CAST(t.typbasetype AS int) " + "END " + "END " /* AS "suggested_system_type_id" */ + ", CASE T2.name COLLATE sys.database_default " + "WHEN \'decimal\' THEN \'decimal(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_precision_helper(T2.name, a.atttypmod) " + "ELSE " + "sys.tsql_type_precision_helper(T2.name, t.typtypmod) " + "END AS sys.VARCHAR(10) ) + \',\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_scale_helper(T2.name, a.atttypmod, false) " + "ELSE " + "sys.tsql_type_scale_helper(T2.name, t.typtypmod, false) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'numeric\' THEN \'numeric(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_precision_helper(T2.name, a.atttypmod) " + "ELSE " + "sys.tsql_type_precision_helper(T2.name, t.typtypmod) " + "END AS sys.VARCHAR(10) ) + \',\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_scale_helper(T2.name, a.atttypmod, false) " + "ELSE " + "sys.tsql_type_scale_helper(T2.name, t.typtypmod, false) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'char\' THEN \'char(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'nchar\' THEN \'nchar(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END /2 AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'binary\' THEN \'binary(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'datetime2\' THEN \'datetime2(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_scale_helper(T2.name, a.atttypmod, false) " + "ELSE " + "sys.tsql_type_scale_helper(T2.name, t.typtypmod, false) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'datetimeoffset\' THEN \'datetimeoffset(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_scale_helper(T2.name, a.atttypmod, false) " + "ELSE " + "sys.tsql_type_scale_helper(T2.name, t.typtypmod, false) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'time\' THEN \'time(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_scale_helper(T2.name, a.atttypmod, false) " + "ELSE " + "sys.tsql_type_scale_helper(T2.name, t.typtypmod, false) " + "END AS sys.VARCHAR(10) ) + \')\' " + "WHEN \'varchar\' THEN " + "CASE WHEN CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END = -1 THEN \'varchar(max)\' " + "ELSE \'varchar(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END AS sys.VARCHAR(10) ) + \')\' " + "END " + "WHEN \'nvarchar\' THEN " + "CASE WHEN CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END = -1 THEN \'nvarchar(max)\' " + "ELSE \'nvarchar(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END /2 AS sys.VARCHAR(10) ) + \')\' " + "END " + "WHEN \'varbinary\' THEN " + "CASE WHEN CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END = -1 THEN \'varbinary(max)\' " + "ELSE \'varbinary(\' + CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END AS sys.VARCHAR(10) ) + \')\' " + "END " + "ELSE T2.name " + "END " /* AS "suggested_system_type_name" */ + ", CASE T2.name COLLATE sys.database_default " + "WHEN \'image\' THEN -1 " + "WHEN \'ntext\' THEN -1 " + "WHEN \'text\' THEN -1 " + "ELSE CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END " + "END " /* AS "suggested_max_length" */ + ", CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_precision_helper(T2.name, a.atttypmod) " + "ELSE " + "sys.tsql_type_precision_helper(T2.name, t.typtypmod) " + "END " /* AS "suggested_precision" */ + ", CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_scale_helper(T2.name, a.atttypmod, false) " + "ELSE " + "sys.tsql_type_scale_helper(T2.name, t.typtypmod, false) " + "END " /* AS "suggested_scale" */ + ", CASE WHEN T2.user_type_id = T2.system_type_id THEN CAST( NULL AS INT ) ELSE T2.user_type_id END " /* AS + * "suggested_user_type_id" */ + ", CASE WHEN T2.user_type_id = T2.system_type_id THEN CAST( NULL AS sysname) ELSE DB_NAME() END " /* AS + * "suggested_user_type_database" */ + ", CASE WHEN T2.user_type_id = T2.system_type_id THEN CAST( NULL AS sysname) ELSE SCHEMA_NAME( T2.schema_id ) END " /* AS + * "suggested_user_type_schema" */ + ", CASE WHEN T2.user_type_id = T2.system_type_id THEN CAST( NULL AS sysname) ELSE T2.name END " /* AS + * "suggested_user_type_name" */ + ", CAST( NULL AS NVARCHAR(4000) ) " /* AS + * "suggested_assembly_qualified_type_name" */ + ", CAST( NULL AS INT ) " /* 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" */ + ", CAST(0 AS sys.bit) " /* 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 T2.name COLLATE sys.database_default " + "WHEN \'tinyint\' THEN 38 " + "WHEN \'smallint\' THEN 38 " + "WHEN \'int\' THEN 38 " + "WHEN \'bigint\' THEN 38 " + "WHEN \'float\' THEN 109 " + "WHEN \'real\' THEN 109 " + "WHEN \'smallmoney\' THEN 110 " + "WHEN \'money\' THEN 110 " + "WHEN \'smalldatetime\' THEN 111 " + "WHEN \'datetime\' THEN 111 " + "WHEN \'binary\' THEN 173 " + "WHEN \'bit\' THEN 104 " + "WHEN \'char\' THEN 175 " + "WHEN \'date\' THEN 40 " + "WHEN \'datetime2\' THEN 42 " + "WHEN \'datetimeoffset\' THEN 43 " + "WHEN \'decimal\' THEN 106 " + "WHEN \'image\' THEN 34 " + "WHEN \'nchar\' THEN 239 " + "WHEN \'ntext\' THEN 99 " + "WHEN \'numeric\' THEN 108 " + "WHEN \'nvarchar\' THEN 231 " + "WHEN \'text\' THEN 35 " + "WHEN \'time\' THEN 41 " + "WHEN \'uniqueidentifier\' THEN 36 " + "WHEN \'varbinary\' THEN 165 " + "WHEN \'varchar\' THEN 167 " + "WHEN \'xml\' THEN 241 " + "ELSE CASE " + "WHEN t.typbasetype = 0 THEN " + "CAST(a.atttypid AS int) " + "ELSE " + "CAST(t.typbasetype AS int) " + "END " + "END " /* AS "suggested_tds_type_id" */ + ", CASE T2.name COLLATE sys.database_default " + "WHEN \'nvarchar\' THEN " + "CASE WHEN CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END = -1 THEN 65535 " + "ELSE CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END " "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) ) + \')\' " + "WHEN \'varbinary\' THEN " + "CASE WHEN CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END = -1 THEN 65535 " + "ELSE CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END " "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) ) + \')\' " + "WHEN \'varchar\' THEN " + "CASE WHEN CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END = -1 THEN 65535 " + "ELSE CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END " "END " - "ELSE T2.name " - "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 " - "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 " - "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 " - "WHEN T2.name COLLATE sys.database_default IN (\'smalldatetime\', \'datetime\') THEN 111 " - "WHEN T2.name COLLATE sys.database_default = \'binary\' THEN 173 " - "WHEN T2.name COLLATE sys.database_default = \'bit\' THEN 104 " - "WHEN T2.name COLLATE sys.database_default = \'char\' THEN 175 " - "WHEN T2.name COLLATE sys.database_default = \'date\' THEN 40 " - "WHEN T2.name COLLATE sys.database_default = \'datetime2\' THEN 42 " - "WHEN T2.name COLLATE sys.database_default = \'datetimeoffset\' THEN 43 " - "WHEN T2.name COLLATE sys.database_default = \'decimal\' THEN 106 " - "WHEN T2.name COLLATE sys.database_default = \'image\' THEN 34 " - "WHEN T2.name COLLATE sys.database_default = \'nchar\' THEN 239 " - "WHEN T2.name COLLATE sys.database_default = \'ntext\' THEN 99 " - "WHEN T2.name COLLATE sys.database_default = \'numeric\' THEN 108 " - "WHEN T2.name COLLATE sys.database_default = \'nvarchar\' THEN 231 " - "WHEN T2.name COLLATE sys.database_default = \'text\' THEN 35 " - "WHEN T2.name COLLATE sys.database_default = \'time\' THEN 41 " - "WHEN T2.name COLLATE sys.database_default = \'uniqueidentifier\' THEN 36 " - "WHEN T2.name COLLATE sys.database_default= \'varbinary\' THEN 165 " - "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 " - "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 " - "WHEN T2.name COLLATE sys.database_default IN (\'decimal\', \'numeric\') THEN 17 " - "WHEN T2.name COLLATE sys.database_default = \'xml\' THEN 8100 " - "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); + "WHEN \'decimal\' THEN 17 " + "WHEN \'numeric\' THEN 17 " + "WHEN \'xml\' THEN 8100 " + "WHEN \'image\' THEN 2147483647 " + "WHEN \'text\' THEN 2147483647 " + "WHEN \'ntext\' THEN 2147483646 " + "ELSE CAST( CASE " + "WHEN a.atttypmod != -1 THEN " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, a.atttypmod) " + "ELSE " + "sys.tsql_type_max_length_helper(T2.name, a.attlen, t.typtypmod) " + "END AS INT ) " + "END " /* AS "suggested_tds_length" */ + "FROM pg_attribute AS a " + "JOIN sys.types AS T2 ON a.atttypid = T2.user_type_id " + "JOIN pg_type AS t ON T2.user_type_id = t.oid " + ", sys.translate_pg_type_to_tsql(t.typbasetype) AS tsql_base_type_name " + "WHERE a.attrelid = %d " + "AND T2.system_type_id = T2.user_type_id " + "AND a.attname = \'%s\' COLLATE sys.database_default "; + + char *query = psprintf(tempq, + undeclaredparams->reloid, + undeclaredparams->targetcolnames[undeclaredparams->paramindexes[call_cntr]]); + + int rc = SPI_execute(query, true, 1); + if (rc != SPI_OK_SELECT) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -1340,18 +1598,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 +1627,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 +1637,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"); - 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); @@ -1418,15 +1681,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 +1705,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); - 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); } /* * 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"); - 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); @@ -1502,21 +1768,237 @@ create_xp_instance_regread_in_master_dbo_internal(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); } -Datum sp_addrole(PG_FUNCTION_ARGS) +Datum +sp_execute_postgresql(PG_FUNCTION_ARGS) +{ + List *parsetree_list; + char *postgresStmt; + Node *stmt; + Node *parsetree; + size_t len; + PlannedStmt *wrapper; + const char *allowed_extns[] = {"pg_stat_statements", "tds_fdw", "fuzzystrmatch"}; + int allowed_extns_size = sizeof(allowed_extns) / sizeof(allowed_extns[0]); + const char *saved_dialect = GetConfigOption("babelfishpg_tsql.sql_dialect", true, true); + Oid current_user_id = GetUserId(); + const char *saved_path = pstrdup(GetConfigOption("search_path", true, true)); + const char *new_path = "public, \"$user\", sys, pg_catalog"; + + PG_TRY(); + { + set_config_option("babelfishpg_tsql.sql_dialect", "postgres", + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + + postgresStmt = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + + if (postgresStmt == NULL) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("statement cannot be NULL"))); + + /* Remove trailing whitespaces */ + len = strlen(postgresStmt); + while (isspace(postgresStmt[len - 1])) + postgresStmt[--len] = 0; + + /* check if input statement is empty after removing trailing spaces */ + if (len == 0) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("statement cannot be NULL"))); + + parsetree_list = raw_parser(postgresStmt, RAW_PARSE_DEFAULT); + + if (list_length(parsetree_list) != 1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("expected 1 statement but got %d statements after parsing", list_length(parsetree_list)))); + + stmt = ((RawStmt *) linitial(parsetree_list))->stmt; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = 0; + wrapper->stmt_len = len; + + parsetree = wrapper->utilityStmt; + + switch (nodeTag(parsetree)) + { + case T_CreateExtensionStmt: + { + CreateExtensionStmt *crstmt = (CreateExtensionStmt *) parsetree; + DefElem *d_schema = NULL; + ListCell *lc; + char *schemaName = NULL; + bool ext_found = false; + + for(int i = 0; i < allowed_extns_size; i++) + { + if(!(strcmp(crstmt->extname, allowed_extns[i]))) + { + ext_found = true; + break; + } + } + + if(!ext_found) + { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("'%s' extension creation is not supported", crstmt->extname))); + } + + if (!superuser_arg(GetSessionUserId()) || !role_is_sa(GetSessionUserId())) + { + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create extension"))); + } + + SetCurrentRoleId(GetSessionUserId(), false); + set_config_option("search_path", new_path, + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); + + foreach(lc, crstmt->options) + { + DefElem *defel = (DefElem *) lfirst(lc); + if (strcmp(defel->defname, "schema") == 0) + { + d_schema = defel; + schemaName = defGetString(d_schema); + } + if (strcmp(defel->defname, "cascade") == 0) + { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("'cascade' is not yet supported in Babelfish"))); + } + } + + if(schemaName != NULL && !(is_shared_schema(schemaName))) + { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("extension creation in '%s' is not supported from TSQL", schemaName))); + } + + /* do this step */ + ProcessUtility(wrapper, + postgresStmt, + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + break; + } + case T_DropStmt: + { + DropStmt *drstmt = (DropStmt *) parsetree; + if (drstmt->removeType != OBJECT_EXTENSION) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("only create/alter/drop extension statements are currently supported in Babelfish"))); + } + SetCurrentRoleId(GetSessionUserId(), false); + + if(drstmt->behavior == DROP_CASCADE) + { + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("'cascade' is not yet supported in Babelfish"))); + } + + /* do this step */ + ProcessUtility(wrapper, + postgresStmt, + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + break; + } + case T_AlterExtensionStmt: + { + SetCurrentRoleId(GetSessionUserId(), false); + /* do this step */ + ProcessUtility(wrapper, + postgresStmt, + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); + + /* make sure later steps can see the object created here */ + CommandCounterIncrement(); + break; + } + case T_AlterObjectSchemaStmt: + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("alter extension schema is not currently supported in Babelfish"))); + break; + } + case T_AlterExtensionContentsStmt: + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("alter extension to Add/Drop object in extension is not currently supported in Babelfish"))); + break; + } + default: + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("only create/alter/drop extension statements are currently supported in Babelfish"))); + break; + } + } + PG_FINALLY(); + { + set_config_option("babelfishpg_tsql.sql_dialect", saved_dialect, + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + set_config_option("search_path", saved_path, + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0, false); + SetCurrentRoleId(current_user_id, false); + + } + PG_END_TRY(); + PG_RETURN_VOID(); +} + +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); + GUC_CONTEXT_CONFIG, + 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 +2006,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 +2060,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 +2073,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 +2088,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1617,10 +2103,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 +2114,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 +2127,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); + GUC_CONTEXT_CONFIG, + 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 +2198,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 +2211,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 +2226,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1751,8 +2241,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 +2251,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 +2262,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 +2271,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); + GUC_CONTEXT_CONFIG, + 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 +2367,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 +2380,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 +2395,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -1907,10 +2410,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 +2422,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 +2444,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); + GUC_CONTEXT_CONFIG, + 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 +2526,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 +2539,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 +2554,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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } @@ -2054,10 +2569,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 +2581,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; @@ -2087,98 +2602,213 @@ gen_sp_droprolemember_subcmds(const char *user, const char *member) return res; } -/* - * Helper function to execute a utility command using - * ProcessUtility(). Caller should make sure their - * inputs are sanitized to prevent unexpected behaviour. - */ static void -exec_utility_cmd_helper(char *query_str) +update_bbf_server_options(char *servername, char *optname, char *optvalue, bool isInsert) { - List *parsetree_list; - Node *stmt; - PlannedStmt *wrapper; + Relation bbf_servers_def_rel; + TupleDesc bbf_servers_def_rel_dsc; + Datum new_record[BBF_SERVERS_DEF_NUM_COLS]; + bool new_record_nulls[BBF_SERVERS_DEF_NUM_COLS]; + bool new_record_repl[BBF_SERVERS_DEF_NUM_COLS]; + ScanKeyData key; + HeapTuple tuple, old_tuple; + TableScanDesc tblscan; + int nargs = BBF_SERVERS_DEF_NUM_COLS - 1; + + MemSet(new_record_repl, false, sizeof(new_record_repl)); + + /* need not check for optname and optvalue when isInsert = true */ + if(isInsert) + { + for(int i = 0; i < nargs; i++) + { + /* check required to allow only timeout server options inside the if block */ + if((strlen(srvOptions_optname[i]) == 13 && strncmp(srvOptions_optname[i], "query timeout", 13) == 0) || (strlen(srvOptions_optname[i]) == 15 && strncmp(srvOptions_optname[i], "connect timeout", 15) == 0)) + { + int32 timeout = atoi(srvOptions_optvalue[i]); + if(strlen(srvOptions_optname[i]) == 13 && strncmp(srvOptions_optname[i], "query timeout", 13) == 0) + new_record[Anum_bbf_servers_def_query_timeout - 1] = Int32GetDatum(timeout); + else + new_record[Anum_bbf_servers_def_connect_timeout - 1] = Int32GetDatum(timeout); + } + } + } + else + { + if (optname && ((strlen(optname) == 13 && strncmp(optname, "query timeout", 13) == 0 ) || (strlen(optname) == 15 && strncmp(optname, "connect timeout", 15) == 0))) + { + int32 timeout; - parsetree_list = raw_parser(query_str, RAW_PARSE_DEFAULT); + /* we throw error when optvalue == NULL or empty */ + if (strlen(optvalue) == 0) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("Invalid option value for %s", optname))); - if (list_length(parsetree_list) != 1) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("Expected 1 statement but get %d statements after parsing", - list_length(parsetree_list)))); - - /* Update the dummy statement with real values */ - stmt = parsetree_nth_stmt(parsetree_list, 0); - - /* Run the built query */ - /* need to make a wrapper PlannedStmt */ - wrapper = makeNode(PlannedStmt); - wrapper->commandType = CMD_UTILITY; - wrapper->canSetTag = false; - wrapper->utilityStmt = stmt; - wrapper->stmt_location = 0; - wrapper->stmt_len = strlen(query_str); - - /* do this step */ - ProcessUtility(wrapper, - query_str, - false, - PROCESS_UTILITY_SUBCOMMAND, - NULL, - NULL, - None_Receiver, - NULL); - - /* make sure later steps can see the object created here */ - CommandCounterIncrement(); + if (optvalue[0] == '+') + optvalue++; + + if (strspn(optvalue, "0123456789") != strlen(optvalue)) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("Invalid option value for %s", optname))); + else + timeout = atoi(optvalue); + + if (timeout < 0) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("%s value provided is out of range",optname))); + + if(strlen(optname) == 13 && strncmp(optname, "query timeout", 13) == 0) + { + new_record_repl[Anum_bbf_servers_def_query_timeout - 1] = true; + new_record[Anum_bbf_servers_def_query_timeout - 1] = Int32GetDatum(timeout); + } + else + { + new_record_repl[Anum_bbf_servers_def_connect_timeout - 1] = true; + new_record[Anum_bbf_servers_def_connect_timeout - 1] = Int32GetDatum(timeout); + } + } + else + { + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("Invalid option provided for sp_serveroption"))); + } + } + + bbf_servers_def_rel = table_open(get_bbf_servers_def_oid(),RowExclusiveLock); + bbf_servers_def_rel_dsc = RelationGetDescr(bbf_servers_def_rel); + + MemSet(new_record_nulls, false, sizeof(new_record_nulls)); + new_record[Anum_bbf_servers_def_servername - 1] = CStringGetTextDatum(servername); + + if(isInsert) + { + tuple = heap_form_tuple(bbf_servers_def_rel_dsc, + new_record, new_record_nulls); + CatalogTupleInsert(bbf_servers_def_rel, tuple); + } + else + { + ScanKeyInit(&key, + Anum_bbf_servers_def_servername, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(servername)); + tblscan = table_beginscan_catalog(bbf_servers_def_rel, 1, &key); + old_tuple = heap_getnext(tblscan, ForwardScanDirection); + + if (!old_tuple) + { + table_endscan(tblscan); + table_close(bbf_servers_def_rel, RowExclusiveLock); + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("The server '%s' does not exist. Use sp_linkedservers to show available servers.", servername))); + } + + for(int i = 1; i < BBF_SERVERS_DEF_NUM_COLS; i++) + { + if(!new_record_repl[i]) + { + bool isNull; + new_record[i] = heap_getattr(old_tuple, i+1, + RelationGetDescr(bbf_servers_def_rel), &isNull); + } + } + + tuple = heap_modify_tuple(old_tuple, bbf_servers_def_rel_dsc, + new_record, new_record_nulls, new_record_repl); + + CatalogTupleUpdate(bbf_servers_def_rel, &tuple->t_self, tuple); + table_endscan(tblscan); + + } + + heap_freetuple(tuple); + table_close(bbf_servers_def_rel, RowExclusiveLock); + +} + +static void +clean_up_bbf_server_option(char *servername) +{ + Relation bbf_servers_def_rel; + HeapTuple scantup; + ScanKeyData key; + TableScanDesc tblscan; + + /* Fetch the relation */ + bbf_servers_def_rel = table_open(get_bbf_servers_def_oid(), RowExclusiveLock); + + /* Search and drop the definition */ + ScanKeyInit(&key, + Anum_bbf_servers_def_servername, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(servername)); + + tblscan = table_beginscan_catalog(bbf_servers_def_rel, 1, &key); + scantup = heap_getnext(tblscan, ForwardScanDirection); + if (HeapTupleIsValid(scantup)) + { + CatalogTupleDelete(bbf_servers_def_rel, &scantup->t_self); + } + table_endscan(tblscan); + table_close(bbf_servers_def_rel, RowExclusiveLock); } 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 *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"))); - - if (strlen(srv_product) == 10 && (strncmp(srv_product, "sql server", 10) == 0)) + 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 (((strlen(provider) == 7) && (strncmp(provider, "sqlncli", 7) == 0)) || - ((strlen(provider) == 10) && (strncmp(provider, "msoledbsql", 10) == 0)) || - ((strlen(provider) == 8) && (strncmp(provider, "sqloledb", 8) == 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)))) { - /* 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 ((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))); + (errcode(ERRCODE_FDW_ERROR), + errmsg("Unsupported provider '%s'. Supported provider is 'tds_fdw'", provider))); if (provstr != NULL) { @@ -2190,11 +2820,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 +2835,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); @@ -2224,6 +2854,8 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) exec_utility_cmd_helper(query.data); + update_bbf_server_options(linked_server, NULL, NULL, true); + /* We throw warnings only if foreign server object creation succeeds */ if (provider_warning) report_info_or_warning(WARNING, "Warning: Using the TDS Foreign data wrapper (tds_fdw) as provider"); @@ -2233,10 +2865,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 +2877,7 @@ sp_addlinkedserver_internal(PG_FUNCTION_ARGS) if (provstr) pfree(provstr); - + if (catalog) pfree(catalog); @@ -2257,53 +2889,54 @@ 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 PUBLIC SERVER OPTIONS + * (username '', password '') * */ - appendStringInfo(&query, "CREATE USER MAPPING FOR CURRENT_USER SERVER \"%s\" ", servername); + appendStringInfo(&query, "CREATE USER MAPPING FOR PUBLIC SERVER \"%s\" ", servername); /* * 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,82 +2978,101 @@ 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"))); + + remove_trailing_spaces(servername); + + /* Check if servername is valid */ + get_foreign_server_oid(servername, false); + initStringInfo(&query); /* - * We prepare the following query to drop a linked server login. This will + * We prepare the following queries to drop a linked server login. This will * be executed using ProcessUtility(): * - * DROP USER MAPPING FOR CURRENT_USER SERVER @SERVERNAME + * DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER @SERVERNAME + * DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER @SERVERNAME + * + * Linked logins were first implemented as PG USER MAPPINGs for the CURRENT_USER which + * was not entirely correct because T-SQL linked logins are not user or login specific. + * To address this we now create user mapping for the PG PUBLIC role internally. * + * To ensure sp_droplinkedsrvlogin works in accordance with both the older and newer + * implementation of linked logins, we try to drop USER MAPPINGs for both the CURRENT_USER + * and PUBLIC PG roles. */ - appendStringInfo(&query, "DROP USER MAPPING FOR CURRENT_USER SERVER \"%s\"", servername); + appendStringInfo(&query, "DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER \"%s\"", servername); + exec_utility_cmd_helper(query.data); + resetStringInfo(&query); + + appendStringInfo(&query, "DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER \"%s\"", servername); 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))) { + /* Remove the server entry from sys.babelfish_server_options catalog */ appendStringInfo(&query, "DROP SERVER \"%s\" CASCADE", linked_srv); exec_utility_cmd_helper(query.data); + clean_up_bbf_server_option(linked_srv); pfree(query.data); if (linked_srv) @@ -2441,89 +3093,146 @@ 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_serveroption_internal(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) - { + char *servername = PG_ARGISNULL(0) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(0))); + char *optionname = PG_ARGISNULL(1) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(1))); + char *optionvalue = PG_ARGISNULL(2) ? NULL : lowerstr(text_to_cstring(PG_GETARG_VARCHAR_PP(2))); + char *newoptionvalue = optionvalue; + + if(!pltsql_enable_linked_servers) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("'sp_serveroption' is not currently supported in Babelfish"))); + + if (servername == NULL) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("@server parameter cannot be NULL"))); + + if (optionname == NULL) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("@optname parameter cannot be NULL"))); + + if (optionvalue == NULL) + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("@optvalue parameter cannot be NULL"))); + + /* we need to ignore trailing spaces in all the arguments */ + remove_trailing_spaces(servername); + remove_trailing_spaces(optionname); + remove_trailing_spaces(newoptionvalue); + + /* we need to ignore leading spaces in optionvalue argument */ + while (*newoptionvalue != '\0' && isspace((unsigned char) *newoptionvalue)) + newoptionvalue++; + + if (optionname && ((strlen(optionname) == 13 && strncmp(optionname, "query timeout", 13) == 0 ) || (strlen(optionname) == 15 && strncmp(optionname, "connect timeout", 15) == 0))) + update_bbf_server_options(servername, optionname, newoptionvalue, false); + else + ereport(ERROR, + (errcode(ERRCODE_FDW_ERROR), + errmsg("Invalid option provided for sp_serveroption. Only 'query timeout' and 'connect timeout' are currently supported."))); + + if(servername) + pfree(servername); + + if(optionname) + pfree(optionname); + + if(optionvalue) + pfree(optionvalue); + + return (Datum) 0; +} + +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) + { /* 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 +3250,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 +3382,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 +3405,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 +3438,171 @@ 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) + +extern bool pltsql_quoted_identifier; + +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, + *curr_relname, + *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 + GUC_CONTEXT_CONFIG, + 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)); + 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 + /* 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; + if (curr_relname != NULL) { + len = strlen(curr_relname); + while(isspace(curr_relname[len - 1])) + curr_relname[--len] = 0; + } + + /* remove delimited identifiers if quoted_identifier is on */ + if (pltsql_quoted_identifier) + { + remove_delimited_identifer(obj_name); + remove_delimited_identifer(schema_name); + if (curr_relname != NULL) { + remove_delimited_identifer(curr_relname); + } + } - // 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 || strcmp(objtype, "TT") == 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 - 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 - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Constraint"))); - } else if (strcmp(objtype, "TT") == 0) { - // TABLE TYPE + } + else if (strcmp(objtype, "TA") == 0 || strcmp(objtype, "TR") == 0) + { + /* 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) + { + /* CONSTRAINT */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Feature not supported: renaming object type Table-Type"))); - } else { + errmsg("Feature not supported: renaming object type Constraint"))); + } + else if (strcmp(objtype, "AL") == 0) + { + /* USER DEFINED TYPES ALIAS*/ + objtype_code = OBJECT_TYPE; + process_util_querystr = "(ALTER TYPE )"; + } + else if (strcmp(objtype, "CO") == 0) + { + objtype_code = OBJECT_COLUMN; + process_util_querystr = "(ALTER TABLE )"; + } + 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_code); + parsetree_list = gen_sp_rename_subcmds(obj_name, new_name, schema_name, objtype_code, curr_relname); - //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,63 +3613,199 @@ 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), + false, + PROCESS_UTILITY_SUBCOMMAND, + NULL, + NULL, + None_Receiver, + NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); - } + } + + rename_extended_property(objtype_code, schema_name, curr_relname, + obj_name, new_name); } 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); + 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), - PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); + GUC_CONTEXT_CONFIG, + PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); PG_RETURN_VOID(); } +/* + * Rename record in extended property as well when calling sp_rename. + */ +static void +rename_extended_property(ObjectType objtype, const char *var_schema_name, + const char *var_major_name, + const char *old_name, const char *new_name) +{ + int db_id = get_cur_db_id(); + char *db_name = get_cur_db_name(); + const char *type; + + if (objtype == OBJECT_TABLE || + objtype == OBJECT_VIEW || + objtype == OBJECT_SEQUENCE || + objtype == OBJECT_PROCEDURE || + objtype == OBJECT_FUNCTION || + objtype == OBJECT_TYPE) + { + /* + * Use old_name as major_name in this routine. + * (refer to gen_sp_rename_subcmds) + */ + if (var_schema_name && old_name) + { + char *schema_name = get_physical_schema_name(db_name, + lowerstr(var_schema_name)); + char *major_name = lowerstr(old_name); + char *new_major_name = lowerstr(new_name); + + /* schema_name doesn't need to truncate again. */ + truncate_tsql_identifier(major_name); + truncate_tsql_identifier(new_major_name); + + if (objtype == OBJECT_TABLE) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE_COLUMN]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + } + else if (objtype == OBJECT_VIEW) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_VIEW]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + } + else if (objtype == OBJECT_SEQUENCE) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_SEQUENCE]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + } + else if (objtype == OBJECT_PROCEDURE) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_PROCEDURE]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + } + else if (objtype == OBJECT_FUNCTION) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_FUNCTION]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + } + else if (objtype == OBJECT_TYPE) + { + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TYPE]; + update_extended_property(db_id, type, schema_name, + major_name, NULL, + Anum_bbf_extended_properties_major_name, + new_major_name); + } + } + } + else if (objtype == OBJECT_COLUMN) + { + if (var_schema_name && var_major_name && old_name) + { + char *schema_name = get_physical_schema_name(db_name, + lowerstr(var_schema_name)); + char *major_name = lowerstr(var_major_name); + char *minor_name = lowerstr(old_name); + char *new_minor_name = lowerstr(new_name); + + /* schema_name doesn't need to truncate again. */ + truncate_tsql_identifier(major_name); + truncate_tsql_identifier(minor_name); + truncate_tsql_identifier(new_minor_name); + + type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE_COLUMN]; + update_extended_property(db_id, type, schema_name, + major_name, minor_name, + Anum_bbf_extended_properties_minor_name, + new_minor_name); + } + } +} + +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; - Node *stmt; + List *res; + Node *stmt; 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 { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Provided objtype is not supported for sp_rename"))); + switch (objtype) + { + 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_TRIGGER: + appendStringInfo(&query, "ALTER TRIGGER dummy ON dummy RENAME TO dummy; "); + appendStringInfo(&query, "ALTER FUNCTION 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), + 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) && (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)))); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("Expected 1 statement but get %d statements after parsing", list_length(res)))); stmt = parsetree_nth_stmt(res, 0); @@ -2917,23 +3813,180 @@ 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 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 + 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 = objtype; + renamestmt->object = (Node *)list_make2(makeString(pstrdup(lowerstr(schemaname))), makeString(pstrdup(lowerstr(objname)))); + 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); return res; } + +static void +remove_delimited_identifer(char *str) +{ + size_t len = strlen(str); + if ((str[0] == '"' && str[len - 1] == '"') || (str[0] == '[' && str[len - 1] == ']')) + { + memmove(str, &str[1], len - 1); + str[len - 2] = '\0'; + } + if isspace(str[0]) + ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong."))); + len = strlen(str); + while (isspace(str[len - 1])) + str[--len] = 0; +} + +Datum +sp_enum_oledb_providers_internal(PG_FUNCTION_ARGS) +{ + /* SPI call input */ + StringInfoData buf; + + const char* provider_name = "tds_fdw"; + + if(!role_is_sa(GetSessionUserId())) + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("Only members of the sysadmin role can execute this stored procedure."))); + + if(GetForeignDataWrapperByName(provider_name, true) == NULL){ + PG_RETURN_VOID(); + } + + initStringInfo(&buf); + appendStringInfo(&buf, "SELECT " + "CAST('%s' AS sys.nvarchar(255)) AS \"Provider Name\", " + "CAST('{' || uuid_in(md5(subquery.provider_desc::text)::cstring) || '}' AS sys.nvarchar(255)) AS \"Parse Name\", " + "CAST(subquery.provider_desc AS sys.nvarchar(255)) AS \"Provider Description\" " + "FROM (" + "SELECT " + "extversion, 'A PostgreSQL foreign data wrapper to connect to TDS databases ' || extversion AS provider_desc " + "FROM pg_catalog.pg_extension " + "WHERE extname = '%s'" + ") subquery;" + , str_toupper(provider_name, strlen(provider_name), C_COLLATION_OID), provider_name); + + PG_TRY(); + { + MemoryContext savedPortalCxt; + SPIPlanPtr plan; + Portal portal; + DestReceiver *receiver; + + int rc; + + savedPortalCxt = PortalContext; + + if (PortalContext == NULL) + PortalContext = MessageContext; + + if ((rc = SPI_connect()) != SPI_OK_CONNECT) + elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc)); + PortalContext = savedPortalCxt; + + if ((plan = SPI_prepare(buf.data, 0, NULL)) == NULL) + elog(ERROR, "SPI_prepare(\"%s\") failed", buf.data); + + if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL) + elog(ERROR, "SPI_cursor_open(\"%s\") failed", buf.data); + + pfree(buf.data); + + receiver = CreateDestReceiver(DestRemote); + SetRemoteDestReceiverParams(receiver, portal); + + /* fetch the result and return the result-set */ + PortalRun(portal, FETCH_ALL, true, true, receiver, receiver, NULL); + + receiver->rDestroy(receiver); + + SPI_cursor_close(portal); + + if ((rc = SPI_finish()) != SPI_OK_FINISH) + elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc)); + } + PG_CATCH(); + { + SPI_finish(); + PG_RE_THROW(); + } + PG_END_TRY(); + + PG_RETURN_VOID(); +} 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..8464578d92 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_sysdatabases_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); @@ -601,6 +602,26 @@ gen_droplogin_subcmds(const char *login) return res; } +/* + * Returns OID of SA of the current database. + * We assume that SA is the DBA of the babelfish DB. + */ +Oid +get_sa_role_oid(void) +{ + HeapTuple tuple; + Oid dba = InvalidOid; + + tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); + if (HeapTupleIsValid(tuple)) + { + dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba; + ReleaseSysCache(tuple); + } + + return dba; +} + /* * Check if the given role is SA of the current database. * We assume that SA is the DBA of the babelfish DB. @@ -608,7 +629,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 +659,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 +673,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 +696,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 +710,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 +732,13 @@ 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; + size_t len; user_input = PG_ARGISNULL(0) ? NULL : text_to_cstring(PG_GETARG_TEXT_PP(0)); db_name = get_cur_db_name(); @@ -724,30 +746,44 @@ user_id(PG_FUNCTION_ARGS) 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. @@ -756,11 +792,12 @@ static char * get_original_login_name(char *login) { Relation relation; - ScanKeyData scanKey; - SysScanDesc scan; + ScanKeyData scanKey; + SysScanDesc scan; HeapTuple tuple; bool isnull; Datum datum; + char *result = NULL; relation = table_open(get_authid_login_ext_oid(), AccessShareLock); @@ -787,10 +824,17 @@ get_original_login_name(char *login) /* original login name should not be NULL. */ Assert(!isnull); + /* + * datum is a pointer to HeapTuple. On the other hand, HeapTuple + * is a pointer to a buffer page. We need to make a copy of that + * datum before closing the scan which releases the buffer. + */ + result = TextDatumGetCString(datum); + systable_endscan(scan); table_close(relation, AccessShareLock); - return TextDatumGetCString(datum); + return result; } @@ -798,9 +842,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 +875,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 +887,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 +917,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 +943,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 +968,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(); @@ -973,21 +1024,73 @@ Datum drop_all_logins(PG_FUNCTION_ARGS) PG_RETURN_INT32(0); } +static void +verify_login_for_bbf_authid_user_ext(RoleSpec *login) +{ + Relation bbf_authid_user_ext_rel; + HeapTuple tuple_user_ext; + ScanKeyData key[2]; + TableScanDesc scan; + const char *cur_db_owner; + NameData *login_name; + char *login_name_str = NULL; + + if (login == NULL || !is_login_name(login->rolename)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("The login '%s' does not exist.", login->rolename))); + + /* Fetch the relation */ + bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), + RowExclusiveLock); + + /* Check for login to user uniqueness in the database */ + login_name = (NameData *) palloc0(NAMEDATALEN); + snprintf(login_name->data, NAMEDATALEN, "%s", login->rolename); + ScanKeyInit(&key[0], + Anum_bbf_authid_user_ext_login_name, + BTEqualStrategyNumber, F_NAMEEQ, + NameGetDatum(login_name)); + ScanKeyInit(&key[1], + Anum_bbf_authid_user_ext_database_name, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(get_cur_db_name())); + + scan = table_beginscan_catalog(bbf_authid_user_ext_rel, 2, key); + tuple_user_ext = heap_getnext(scan, ForwardScanDirection); + pfree(login_name); + + if (tuple_user_ext != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION), + errmsg("Existing user already maps to login '%s' in current database.", login->rolename))); + + table_endscan(scan); + 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()); + if (strcmp(login_name_str, cur_db_owner) == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION), + errmsg("The login already has an account under a different user name."))); +} + void add_to_bbf_authid_user_ext(const char *user_name, const char *orig_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 +1112,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 +1134,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 +1157,11 @@ 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; + char *login_name_str = NULL; /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -1079,7 +1181,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,52 +1193,8 @@ 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; - - if (login == NULL || !is_login_name(login->rolename)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("The login '%s' does not exist.", login->rolename))); - - /* Fetch the relation */ - bbf_authid_user_ext_rel = table_open(get_authid_user_ext_oid(), - RowExclusiveLock); - - /* Check for login to user uniqueness in the database */ - login_name = (NameData *) palloc0(NAMEDATALEN); - snprintf(login_name->data, NAMEDATALEN, "%s", login->rolename); - ScanKeyInit(&key[0], - Anum_bbf_authid_user_ext_login_name, - BTEqualStrategyNumber, F_NAMEEQ, - NameGetDatum(login_name)); - ScanKeyInit(&key[1], - Anum_bbf_authid_user_ext_database_name, - BTEqualStrategyNumber, F_TEXTEQ, - CStringGetTextDatum(get_cur_db_name())); - - scan = table_beginscan_catalog(bbf_authid_user_ext_rel, 2, key); - - tuple_user_ext = heap_getnext(scan, ForwardScanDirection); - if (tuple_user_ext != NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION), - errmsg("Existing user already maps to login '%s' in current database.", login->rolename))); - - table_endscan(scan); - table_close(bbf_authid_user_ext_rel, RowExclusiveLock); - + verify_login_for_bbf_authid_user_ext(login); login_name_str = login->rolename; - cur_db_owner = get_owner_of_db((const char *)get_cur_db_name()); - - if (strcmp(login_name_str, cur_db_owner) == 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_ROLE_SPECIFICATION), - errmsg("The login already has an account under a different user name."))); - } /* Add to the catalog table. Adds current database name by default */ @@ -1147,17 +1205,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 +1223,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_sysdatabases_name, + db_rel->rd_att, + &is_null); db_name = TextDatumGetCString(db_name_datum); dbo_role = get_dbo_role_name(db_name); @@ -1196,7 +1254,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 +1281,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 +1296,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 +1344,22 @@ 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; + RoleSpec *login = NULL; + char *default_schema = NULL; + char *new_user_name = NULL; + char *physical_name = NULL; + char *login_name_str = NULL; if (sql_dialect != SQL_DIALECT_TSQL) return; @@ -1310,11 +1374,25 @@ alter_bbf_authid_user_ext(AlterRoleStmt *stmt) if (defel->arg) default_schema = strVal(defel->arg); } - if (strcmp(defel->defname, "rename") == 0) + else if (strcmp(defel->defname, "rename") == 0) { if (defel->arg) new_user_name = strVal(defel->arg); } + else if (strcmp(defel->defname, "rolemembers") == 0) + { + List *rolemembers = NIL; + + rolemembers = (List *) defel->arg; + login = (RoleSpec *) linitial(rolemembers); + } + } + + if (login != NULL) + { + verify_login_for_bbf_authid_user_ext(login); + login_name_str = login->rolename; + } /* Fetch the relation */ @@ -1322,7 +1400,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, @@ -1373,6 +1451,12 @@ alter_bbf_authid_user_ext(AlterRoleStmt *stmt) new_record_repl_user_ext[USER_EXT_DEFAULT_SCHEMA_NAME] = true; } + if (login_name_str) + { + new_record_user_ext[USER_EXT_LOGIN_NAME] = CStringGetDatum(pstrdup(login_name_str)); + new_record_repl_user_ext[USER_EXT_LOGIN_NAME] = true; + } + new_tuple = heap_modify_tuple(tuple, bbf_authid_user_ext_dsc, new_record_user_ext, @@ -1391,10 +1475,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 +1520,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 +1543,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 +1553,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 +1576,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 +1601,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 +1613,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 +1648,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 +1669,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 +1694,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 +1713,7 @@ check_alter_role_stmt(GrantRoleStmt *stmt) bool is_empty_role(Oid roleid) { - CatCList *memlist; + CatCList *memlist; if (roleid == InvalidOid) return true; @@ -1634,7 +1725,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 +1746,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 +1775,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 +1808,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 +1819,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 +1831,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 +1843,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 +1854,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 +1867,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 +1878,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; + 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 + /* 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 +1919,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,19 +1933,23 @@ 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); dsc = RelationGetDescr(bbf_domain_mapping_rel); - ScanKeyInit(&scanKey, - Anum_bbf_domain_mapping_netbios_domain_name, - BTEqualStrategyNumber, F_TEXTEQ, - CStringGetTextDatum(netbios_domain)); + ScanKeyEntryInitialize(&scanKey, + 0, + Anum_bbf_domain_mapping_netbios_domain_name, + BTEqualStrategyNumber, + InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, + CStringGetTextDatum(netbios_domain)); scan = systable_beginscan(bbf_domain_mapping_rel, get_bbf_domain_mapping_idx_oid(), @@ -1862,12 +1958,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 +1982,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 +1995,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 +2028,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 +2062,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 +2102,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))); @@ -2037,8 +2136,6 @@ babelfish_add_domain_mapping_entry_internal(PG_FUNCTION_ARGS) new_record = palloc0(sizeof(Datum) * BBF_DOMAIN_MAPPING_NUM_COLS); new_record_nulls = palloc0(sizeof(bool) * BBF_DOMAIN_MAPPING_NUM_COLS); - MemSet(new_record_nulls, false, sizeof(new_record_nulls)); - new_record[0] = PG_GETARG_DATUM(0); new_record[1] = PG_GETARG_DATUM(1); @@ -2057,7 +2154,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 +2171,7 @@ babelfish_add_domain_mapping_entry_internal(PG_FUNCTION_ARGS) edata->message))); } PG_END_TRY(); - + return (Datum) 0; } @@ -2088,32 +2185,33 @@ 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); - ScanKeyInit(&scanKey, - Anum_bbf_domain_mapping_netbios_domain_name, - BTEqualStrategyNumber, F_TEXTEQ, - PG_GETARG_DATUM(0)); + ScanKeyEntryInitialize(&scanKey, 0, + Anum_bbf_domain_mapping_netbios_domain_name, + BTEqualStrategyNumber, InvalidOid, + tsql_get_server_collation_oid_internal(false), + F_TEXTEQ, PG_GETARG_DATUM(0)); scan = systable_beginscan(bbf_domain_mapping_rel, get_bbf_domain_mapping_idx_oid(), @@ -2132,7 +2230,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 +2248,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,52 +2266,79 @@ 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++; } 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. */ 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..626534f194 100644 --- a/contrib/babelfishpg_tsql/src/rolecmds.h +++ b/contrib/babelfishpg_tsql/src/rolecmds.h @@ -49,11 +49,12 @@ #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 Oid get_sa_role_oid(void); extern bool tsql_has_pgstat_permissions(Oid roleid); extern bool tsql_has_linked_srv_permissions(Oid roleid); extern bool is_alter_server_stmt(GrantRoleStmt *stmt); @@ -75,8 +76,10 @@ 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 windows_domain_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..3810e521ed 100644 --- a/contrib/babelfishpg_tsql/src/session.c +++ b/contrib/babelfishpg_tsql/src/session.c @@ -7,6 +7,7 @@ #include "utils/formatting.h" #include "utils/guc.h" #include "utils/hsearch.h" +#include "catalog.h" #include #include "catalog.h" @@ -14,25 +15,28 @@ #include "multidb.h" #include "session.h" #include "pltsql.h" +#include "guc.h" /* 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 +54,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 +63,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 +79,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 +116,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 +133,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 +148,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 +184,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,22 +198,30 @@ 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 - dbid = current_db_id; + { + if (!IS_TDS_CLIENT() && pltsql_psql_logical_babelfish_db_name) + dbid = get_db_id(pltsql_psql_logical_babelfish_db_name); + else + dbid = current_db_id; + } + if (!DbidIsValid(dbid)) { @@ -218,10 +232,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); @@ -230,18 +245,21 @@ Datum babelfish_db_name(PG_FUNCTION_ARGS) if (dbid == 1) { - dbname = palloc((strlen("master") + 1) * sizeof(char)); - strncpy(dbname, "master", MAX_BBF_NAMEDATALEND); + int dbnamelen = strlen("master"); + dbname = palloc0((dbnamelen + 1) * sizeof(char)); + strncpy(dbname, "master", dbnamelen); } else if (dbid == 2) { - dbname = palloc((strlen("tempdb") + 1) * sizeof(char)); - strncpy(dbname, "tempdb", MAX_BBF_NAMEDATALEND); + int dbnamelen = strlen("tempdb"); + dbname = palloc0((dbnamelen + 1) * sizeof(char)); + strncpy(dbname, "tempdb", dbnamelen); } else if (dbid == 4) { - dbname = palloc((strlen("msdb") + 1) * sizeof(char)); - strncpy(dbname, "msdb", MAX_BBF_NAMEDATALEND); + int dbnamelen = strlen("msdb"); + dbname = palloc0((dbnamelen + 1) * sizeof(char)); + strncpy(dbname, "msdb", dbnamelen); } else dbname = get_db_name(dbid); @@ -252,28 +270,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 +302,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 +314,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 +327,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 +359,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..c608eb4f09 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,55 @@ 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", + "date_bucket", + "datename", + "datepart", + "datetrunc", + "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..e41ec44e76 100644 --- a/contrib/babelfishpg_tsql/src/stmt_walker.c +++ b/contrib/babelfishpg_tsql/src/stmt_walker.c @@ -5,133 +5,146 @@ * 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_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_KILL: + 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_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: + case PLTSQL_STMT_CHANGE_DBOWNER: + case PLTSQL_STMT_GRANTSCHEMA: + case PLTSQL_STMT_FULLTEXTINDEX: + case PLTSQL_STMT_DBCC: + 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 +156,75 @@ 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(KILL, kill) + DISPATCH(INSERT_BULK, insert_bulk) + DISPATCH(SET_EXPLAIN_MODE, set_explain_mode) + DISPATCH(GRANTDB, grantdb) + DISPATCH(CHANGE_DBOWNER, change_dbowner) + DISPATCH(DBCC, dbcc) + DISPATCH(GRANTSCHEMA, grantschema) + DISPATCH(FULLTEXTINDEX, fulltextindex) + + /* 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..96e58e89eb 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,9 +65,10 @@ 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_kill_act) ACTION_SIGNITURE(kill); typedef bool (*Stmt_init_act) ACTION_SIGNITURE(init); typedef bool (*Stmt_query_set_act) ACTION_SIGNITURE(query_set); typedef bool (*Stmt_try_catch_act) ACTION_SIGNITURE(try_catch); @@ -86,8 +87,12 @@ typedef bool (*Stmt_usedb_act) ACTION_SIGNITURE(usedb); 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); +typedef bool (*Stmt_change_dbowner_act) ACTION_SIGNITURE(change_dbowner); +typedef bool (*Stmt_dbcc_act) ACTION_SIGNITURE(dbcc); +typedef bool (*Stmt_grantschema_act) ACTION_SIGNITURE(grantschema); +typedef bool (*Stmt_fulltextindex_act) ACTION_SIGNITURE(fulltextindex); - /* 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 +102,65 @@ 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_kill_act kill_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; + Stmt_change_dbowner_act change_dbowner_act; + Stmt_dbcc_act dbcc_act; + Stmt_grantschema_act grantschema_act; + Stmt_fulltextindex_act fulltextindex_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 +171,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..6126e60768 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,16 +398,14 @@ 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]) { @@ -404,6 +414,7 @@ prepare_format_string(StringInfo buf, char *msg_string, int nargs, continue; } + arg = args[i]; typid = argtypes[i]; type = TypeCategory(typid); @@ -411,17 +422,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 +446,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 +454,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 +464,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 +476,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 +498,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 +858,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/table_variable_mvcc.c b/contrib/babelfishpg_tsql/src/table_variable_mvcc.c new file mode 100644 index 0000000000..f223e2a4f7 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/table_variable_mvcc.c @@ -0,0 +1,602 @@ +#include "postgres.h" + +#include "table_variable_mvcc.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/multixact.h" +#include "access/subtrans.h" +#include "access/tableam.h" +#include "access/transam.h" +#include "access/xact.h" +#include "access/xlog.h" +#include "storage/bufmgr.h" +#include "storage/procarray.h" +#include "utils/builtins.h" +#include "utils/combocid.h" +#include "utils/memutils.h" +#include "utils/snapmgr.h" + +#include "pltsql.h" + +/* +* MVCC is different for Table Variables because Table Variables +* are not supposed to be sensitive to ROLLBACK. All DML operations +* are visible regardless of transaction performing the DML +* COMMITs or ABORTs. DML operation is not visible if and only if the +* the transaction performing the DML hit an error (ie: unexpected rollback) +* This map keeps track of failed transaction ids +*/ +static HTAB *table_variable_failed_xid_map = NULL; + +void +init_failed_transactions_map(void) +{ + HASHCTL ctl; + + if (table_variable_failed_xid_map) + return; + + ctl.keysize = sizeof(TransactionId); + ctl.entrysize = sizeof(TransactionId); + ctl.hcxt = CacheMemoryContext; + + table_variable_failed_xid_map = + hash_create("Failed Transactions Map", + 32, + &ctl, + HASH_ELEM | HASH_CONTEXT | HASH_BLOBS); +} + +void +destroy_failed_transactions_map(void) +{ + if (!table_variable_failed_xid_map) + return; + + hash_destroy(table_variable_failed_xid_map); + table_variable_failed_xid_map = NULL; +} + +void +add_failed_transaction(TransactionId xid) +{ + bool found = false; + + if (!table_variable_failed_xid_map) + return; + + hash_search(table_variable_failed_xid_map, (void *) &xid, HASH_ENTER, &found); +} + +bool +find_failed_transaction(TransactionId xid) +{ + bool found = false; + + Assert(table_variable_failed_xid_map); + hash_search(table_variable_failed_xid_map, (void *) &xid, HASH_FIND, &found); + return found; +} + +static bool +TVHeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer) +{ + return true; +} + + +/* + * TVHeapTupleSatisfiesMVCC + * + * Table Variables are not sensitive to rollbacks and are meant for use on current session only. + * This is equivalent to HeapTupleSatisfiesMVCC for regular tables. + * However, it ignores XidInMVCCSnapshot() because it only cares whether the xid is committed or unexpectedly rolled back. + * It still uses snapshot because it needs the command id in cases when xid is the current transaction. + * + * 1. A row is VISIBLE when: + * 1.1. XMIN is NOT-IN-PROGRESS anymore (xmin already COMMITTED/ROllBACK) + * 1.1.1. XMAX is NOT set (not yet DELETED/UPDATED) + * 1.1.2. XMAX failed unexpectedly + * 1.1.3. XMAX is set but (tuple->cid >= snapshotcid) to guard against the Halloween problem + * 1.2. XMIN is current transaction + * 1.2.1. INSERTed before current command (tuple->cid < snapshotcid) to guard the Halloween problem + * 1.2.2. XMAX is NOT set (not yet DELETED/UPDATED) + * 1.2.3. XMAX is set but (tuple->cid >= snapshotcid) to guard against the Halloween problem + * 1.2.4. XMAX is set but by a previous subtransaction that failed unexpectedly + * + * 2. A row is INVISIBLE when: + * 2.1. XMIN is NOT-IN-PROGRESS anymore + * 2.1.1. XMIN Failed unexpectedly + * 2.1.2. XMIN INVALID flag is set by previous scan operations + * 2.1.3. updated/deleted by previous command in the same transaction + * 2.2. XMIN is current transaction + * 2.2.1. Inserted by current command. eg: INSERT INTO t SELECT * FROM t (tuple->cid >= snapshotcid) + * 2.2.2. updated/deleted by previous command in the same transaction (tuple->cid < snapshotcid) + * 2.2.3. INSERTed by a previous subtransaction that failed unexpectedly + * 2.3. XMAX committed or clean Rollback + * 2.4. XMAX is current transaction + * 2.4.1. updated/deleted by a previous command (tuple->cid < snapshotcid) + */ +static bool +TVHeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer) +{ + HeapTupleHeader tuple = htup->t_data; + + Assert(ItemPointerIsValid(&htup->t_self)); + Assert(htup->t_tableOid != InvalidOid); + + /* The HEAP_XMIN_COMMITTED hint bit is not yet set */ + if (!HeapTupleHeaderXminCommitted(tuple)) + { + if (HeapTupleHeaderXminInvalid(tuple)) /* Case 2.1.2 in comment section */ + return false; + + else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple))) + { + if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid) /* Inserted after scan started. Case 2.2.1 in comment section */ + return false; + + /* There should not be any locking in table variable at this point */ + Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); + Assert((tuple->t_infomask & HEAP_XMAX_IS_MULTI) == 0); + + if (tuple->t_infomask & HEAP_XMAX_INVALID) + return true; + + /* xmax is current txn or some subtxn of current txn that committed */ + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) /* Case 1.2.3 and 2.2.2 */ + return (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid); + + if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) /* Case 1.2.5 */ + { + /* deleting subtransaction must have aborted unexpectedly */ + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return true; + } + } + else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetRawXmin(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmin(tuple))) /* This is case 2.2.3 in comment section */ + { + /* xmin is aborted unexpectedly */ + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); + return false; + } + } + + /* by here, the inserting transaction is "considered" committed */ + + /* There should not be any locking in table variable at this point */ + Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); + Assert((tuple->t_infomask & HEAP_XMAX_IS_MULTI) == 0); + + if ((tuple->t_infomask & HEAP_XMAX_INVALID)) /* Case 1.1.1 comment section */ + return true; + + /* The HEAP_XMAX_COMMITTED hint bit is not yet set */ + if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) + { + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) + return (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid); /* Cases 1.2.4 and 2.4.1 in comment section */ + + if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) /* Case 1.1.2 xmax must have aborted unexpectedly or crashed */ + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return true; + } + } + + /* xmax transaction committed or clean rollback. Case 2.3 in comment section */ + return false; +} + + +/* + * TVHeapTupleSatisfiesDirtyOrSelf + * + * In general, HeapTupleSatisfiesSelf and HeapTupleSatisfiesDirty are the same + * as far as effects of the current transaction and committed/aborted xacts are concerned. + * The difference is that HeapTupleSatisfiesSelf also includes the effects of other xacts still in progress. + * This is not the case for Table Variables because tables are per-session. + * Hence for table variables, SNAPSHOT_SELF and SNAPSHOT_DIRTY are the same + * + * 1. A row is VISIBLE when: + * 1.1. XMIN is COMMITTED or expected ROLLBACK or Current Transaction + * 1.1.1. XMAX is INVALID + * 1.1.2. XMAX failed unexpectedly + * 1.1.3. XMAX is in-progress + * + * 2. A row is INVISIBLE when: + * 2.0. XMIN INVALID hint bit is set by previous scan operations + * 2.1. XMIN Failed unexpectedly + * 2.3. XMAX committed or clean Rollback + */ +static bool +TVHeapTupleSatisfiesDirtyOrSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer) +{ + HeapTupleHeader tuple = htup->t_data; + + Assert(ItemPointerIsValid(&htup->t_self)); + Assert(htup->t_tableOid != InvalidOid); + + if (snapshot->snapshot_type == SNAPSHOT_DIRTY) + { + snapshot->xmin = snapshot->xmax = InvalidTransactionId; + snapshot->speculativeToken = 0; + } + + if (!HeapTupleHeaderXminCommitted(tuple)) + { + if (HeapTupleHeaderXminInvalid(tuple)) /* Case 2.0 in comment section */ + return false; + + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple))) + { + if (tuple->t_infomask & HEAP_XMAX_INVALID) + return true; /* Case 1.1.1 */ + + Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); + Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); + + if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return true; /* Case 1.1.2 */ + } + + return false; /* Case 2.3 in comment section */ + } + + /* Table Variables are per-session so if xmin is active it would be true above */ + Assert(!TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))); + + if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetRawXmin(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmin(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); + return false; /* Case 2.1 in comment section */ + } + } + + /* by here, the inserting transaction is considered committed */ + + if (tuple->t_infomask & HEAP_XMAX_INVALID) /* Case 1.1.1 */ + return true; + + if (tuple->t_infomask & HEAP_XMAX_COMMITTED) + return false; /* Case 1.1.3 */ + + Assert(!(HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))); + Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); + + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) /* Case 2.4 and 1.1.3 */ + return false; + + /* Table Variables are per-session so if xmax is active it would be true above */ + Assert(!TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))); + + if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return true; /* Case 1.1.3 */ + } + + /* xmax transaction considered committed */ + return false; /* Case 2.3 */ +} + +static bool +TVHeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer) +{ + HeapTupleHeader tuple = htup->t_data; + + Assert(ItemPointerIsValid(&htup->t_self)); + Assert(htup->t_tableOid != InvalidOid); + + if (!HeapTupleHeaderXminCommitted(tuple)) + { + if (HeapTupleHeaderXminInvalid(tuple)) + return false; + + /* + * An invalid Xmin can be left behind by a speculative insertion that + * is canceled by super-deleting the tuple. This also applies to + * TOAST tuples created during speculative insertion. + */ + else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple))) + return false; + } + + /* otherwise assume the tuple is valid for TOAST. */ + return true; +} + +static bool +TVHeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer) +{ + TransactionId dead_after = InvalidTransactionId; + HTSV_Result res; + + res = TVHeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after); + + if (res == HEAPTUPLE_RECENTLY_DEAD) + { + Assert(TransactionIdIsValid(dead_after)); + + if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after)) + res = HEAPTUPLE_DEAD; + } + else + Assert(!TransactionIdIsValid(dead_after)); + + return res != HEAPTUPLE_DEAD; +} + +/* + * HeapTupleSatisfiesVisibility + * True iff heap tuple satisfies a time qual. + * + * Notes: + * Assumes heap tuple is valid, and buffer at least share locked. + * + * Hint bits in the HeapTuple's t_infomask may be updated as a side effect; + * if so, the indicated buffer is marked dirty. + */ +bool +TVHeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer) +{ + switch (snapshot->snapshot_type) + { + case SNAPSHOT_MVCC: + return TVHeapTupleSatisfiesMVCC(tup, snapshot, buffer); + break; + case SNAPSHOT_ANY: + return TVHeapTupleSatisfiesAny(tup, snapshot, buffer); + break; + case SNAPSHOT_SELF: + case SNAPSHOT_DIRTY: + return TVHeapTupleSatisfiesDirtyOrSelf(tup, snapshot, buffer); + break; + case SNAPSHOT_TOAST: + return TVHeapTupleSatisfiesToast(tup, snapshot, buffer); + break; + case SNAPSHOT_NON_VACUUMABLE: + return TVHeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer); + break; + + case SNAPSHOT_HISTORIC_MVCC: + default: + ereport(ERROR, (errmsg("Unsupported snapshot type %d for Table Variables", snapshot->snapshot_type))); + break; + } + + return false; /* keep compiler quiet */ + +} + + +/* + * TVHeapTupleSatisfiesUpdate + * + * Counterpart of HeapTupleSatisfiesUpdate. + * The only difference is this function is not rollback sensitive. + */ +TM_Result TVHeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer) +{ + HeapTupleHeader tuple = htup->t_data; + + Assert(ItemPointerIsValid(&htup->t_self)); + Assert(htup->t_tableOid != InvalidOid); + + if (!HeapTupleHeaderXminCommitted(tuple)) + { + if (HeapTupleHeaderXminInvalid(tuple)) + return TM_Invisible; + + else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple))) + { + if (HeapTupleHeaderGetCmin(tuple) >= curcid) + return TM_Invisible; /* inserted after scan started */ + + if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ + return TM_Ok; + + /* These should not be supported for Table Variables at this point */ + Assert(!(HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))); + Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); + + /* deleting subtransaction must have aborted */ + if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return TM_Ok; + } + + if (HeapTupleHeaderGetCmax(tuple) >= curcid) + return TM_SelfModified; /* updated after scan started */ + else + return TM_Invisible; /* updated before scan started */ + } + + /* Table Variables are per-session so if xmin is active it would be true above */ + Assert(!TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))); + + if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetRawXmin(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmin(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); + return TM_Invisible; + } + } + + /* by here, the inserting transaction is "considered" committed */ + if (tuple->t_infomask & HEAP_XMAX_INVALID) + return TM_Ok; + + Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); + Assert(!(HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))); + + if (tuple->t_infomask & HEAP_XMAX_COMMITTED) + { + if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid)) + return TM_Updated; /* updated by other */ + else + return TM_Deleted; /* deleted by other */ + } + + if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) + { + if (HeapTupleHeaderGetCmax(tuple) >= curcid) + return TM_SelfModified; /* updated after scan started */ + else + return TM_Invisible; /* updated before scan started */ + } + + /* Table Variables are per-session so if xmax is active it would be true above */ + Assert(!TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))); + + if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return TM_Ok; + } + + /* xmax transaction committed */ + if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid)) + return TM_Updated; /* updated by other */ + else + return TM_Deleted; /* deleted by other */ +} + + +/* + * HeapTupleSatisfiesVacuum + * + * Determine the status of tuples for VACUUM purposes. Here, what + * we mainly want to know is if a tuple is potentially visible to *any* + * running transaction. If so, it can't be removed yet by VACUUM. + * + * OldestXmin is a cutoff XID (obtained from + * GetOldestNonRemovableTransactionId()). Tuples deleted by XIDs >= + * OldestXmin are deemed "recently dead"; they might still be visible to some + * open transaction, so we can't remove them, even if we see that the deleting + * transaction has committed. + */ +HTSV_Result +TVHeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, + Buffer buffer) +{ + TransactionId dead_after = InvalidTransactionId; + HTSV_Result res; + + res = TVHeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after); + + if (res == HEAPTUPLE_RECENTLY_DEAD) + { + Assert(TransactionIdIsValid(dead_after)); + + if (TransactionIdPrecedes(dead_after, OldestXmin)) + res = HEAPTUPLE_DEAD; + } + else + Assert(!TransactionIdIsValid(dead_after)); + + return res; +} + + +/* + * Work horse for TVHeapTupleSatisfiesVacuum and similar routines. + * + * In contrast to HeapTupleSatisfiesVacuum this routine, when encountering a + * tuple that could still be visible to some backend, stores the xid that + * needs to be compared with the horizon in *dead_after, and returns + * HEAPTUPLE_RECENTLY_DEAD. The caller then can perform the comparison with + * the horizon. This is e.g. useful when comparing with different horizons. + * + * Note: HEAPTUPLE_DEAD can still be returned here, e.g. if the inserting + * transaction aborted. + */ +HTSV_Result +TVHeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after) +{ + HeapTupleHeader tuple = htup->t_data; + + Assert(ItemPointerIsValid(&htup->t_self)); + Assert(htup->t_tableOid != InvalidOid); + Assert(dead_after != NULL); + + *dead_after = InvalidTransactionId; + + /* + * Has inserting transaction committed? + * + * If the inserting transaction aborted, then the tuple was never visible + * to any other transaction, so we can delete it immediately. + */ + if (!HeapTupleHeaderXminCommitted(tuple)) + { + if (HeapTupleHeaderXminInvalid(tuple)) + return HEAPTUPLE_DEAD; + + else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple))) + { + TransactionId xmax; + if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ + return HEAPTUPLE_LIVE; + + xmax = HeapTupleHeaderGetUpdateXid(tuple); + if (TransactionIdIsCurrentTransactionId(xmax)) { + *dead_after = HeapTupleHeaderGetRawXmax(tuple); + return HEAPTUPLE_RECENTLY_DEAD; + } + else if (find_failed_transaction(xmax)) + return HEAPTUPLE_LIVE; + + } + else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetRawXmin(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmin(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); + return HEAPTUPLE_DEAD; + } + + } + + /* + * Okay, the inserter committed or had a clean rollback, so it was good at some point. + * Now what about the deleting transaction? + */ + if (tuple->t_infomask & HEAP_XMAX_INVALID) + return HEAPTUPLE_LIVE; + + Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); + Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); + + if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) + { + if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); + else if (find_failed_transaction(HeapTupleHeaderGetRawXmax(tuple))) + { + HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); + return HEAPTUPLE_LIVE; + } + } + + /* + * Deleter is not in-progress anymore, allow caller to check if it was recent enough that + * some open transactions could still see the tuple. + */ + *dead_after = HeapTupleHeaderGetRawXmax(tuple); + return HEAPTUPLE_RECENTLY_DEAD; +} diff --git a/contrib/babelfishpg_tsql/src/table_variable_mvcc.h b/contrib/babelfishpg_tsql/src/table_variable_mvcc.h new file mode 100644 index 0000000000..060cde9f10 --- /dev/null +++ b/contrib/babelfishpg_tsql/src/table_variable_mvcc.h @@ -0,0 +1,16 @@ +#ifndef TABLE_VARIABLE_HEAPAM_H +#define TABLE_VARIABLE_HEAPAM_H + +#include "access/heapam.h" + +extern bool TVHeapTupleSatisfiesVisibility(HeapTuple tuple, Snapshot snapshot, Buffer buffer); +extern TM_Result TVHeapTupleSatisfiesUpdate(HeapTuple tuple, CommandId curcid, Buffer buffer); +extern HTSV_Result TVHeapTupleSatisfiesVacuum(HeapTuple stup, TransactionId OldestXmin, Buffer buffer); +extern HTSV_Result TVHeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after); + +extern void init_failed_transactions_map(void); +extern void destroy_failed_transactions_map(void); +extern void add_failed_transaction(TransactionId xid); +extern bool find_failed_transaction(TransactionId xid); + +#endif \ No newline at end of file diff --git a/contrib/babelfishpg_tsql/src/tablecmds.c b/contrib/babelfishpg_tsql/src/tablecmds.c index b131cc3639..a53d13881e 100644 --- a/contrib/babelfishpg_tsql/src/tablecmds.c +++ b/contrib/babelfishpg_tsql/src/tablecmds.c @@ -29,147 +29,159 @@ #include "parser/parse_expr.h" #include "parser/parse_type.h" #include "parser/parse_collate.h" +#include "parser/scansup.h" #include "utils/fmgroids.h" #include "utils/syscache.h" #include "utils/lsyscache.h" #include "utils/builtins.h" +#include "catalog/pg_trigger_d.h" #include "../src/multidb.h" #include "../src/session.h" #include "catalog.h" +#include "extendedproperty.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); - 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); + DropBehavior behavior = DROP_CASCADE; + ObjectAddress trigAddress; + + /* 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) + { + trigAddress.classId = TriggerRelationId; + trigAddress.objectId = pg_trigger->oid; + trigAddress.objectSubId = 0; + performDeletion(&trigAddress, behavior, PERFORM_DELETION_INTERNAL); + } + } + + 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 @@ -192,7 +204,9 @@ pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum) Relation depRel; ScanKeyData key[3]; SysScanDesc scan; - HeapTuple depTup; + HeapTuple depTup, tuple; + char *schema_name = NULL, + *minor_name = NULL; /* Call previous hook if exists */ if (prev_InvokePreDropColumnHook) @@ -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), @@ -260,6 +277,25 @@ pltsql_PreDropColumnHook(Relation rel, AttrNumber attnum) systable_endscan(scan); table_close(depRel, RowExclusiveLock); + + /* Delete extended property as well */ + + /* Get minor_name */ + tuple = SearchSysCacheAttNum(RelationGetRelid(rel), attnum); + if (!HeapTupleIsValid(tuple)) + return; + minor_name = pstrdup(NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname)); + ReleaseSysCache(tuple); + + /* Get schema_name */ + schema_name = get_namespace_name(RelationGetNamespace(rel)); + + if (schema_name && minor_name) + { + const char *type = ExtendedPropertyTypeNames[EXTENDED_PROPERTY_TABLE_COLUMN]; + delete_extended_property(get_cur_db_id(), type, schema_name, + RelationGetRelationName(rel), minor_name); + } } static bool @@ -269,20 +305,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 +326,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 +343,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 +378,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 +388,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 +406,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 +462,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 +489,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 +514,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/timezone.h b/contrib/babelfishpg_tsql/src/timezone.h new file mode 100644 index 0000000000..49c66fb81e --- /dev/null +++ b/contrib/babelfishpg_tsql/src/timezone.h @@ -0,0 +1,736 @@ +#ifndef TSQL_TIMEZONE_H +#define TSQL_TIMEZONE_H + +static const struct +{ + const char *stdname; /* Windows name of standard timezone */ + const char *dstname; /* Windows name of daylight timezone */ + const char *pgtzname; /* Name of pgsql timezone to map to */ +} win32_tzmap[] = + + { + /* + * This list was built from the contents of the registry at + * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time + * Zones on Windows 7, Windows 10, and Windows Server 2019. Some recent + * additions have been made by comparing to the CLDR project's + * windowsZones.xml file. + * + * The zones have been matched to IANA timezones based on CLDR's mapping + * for "territory 001". + */ + { + /* (UTC+04:30) Kabul */ + "afghanistan standard time", "Afghanistan Daylight Time", + "Asia/Kabul" + }, + { + /* (UTC-09:00) Alaska */ + "alaskan standard time", "Alaskan Daylight Time", + "America/Anchorage" + }, + { + /* (UTC-10:00) Aleutian Islands */ + "aleutian standard time", "Aleutian Daylight Time", + "America/Adak" + }, + { + /* (UTC+07:00) Barnaul, Gorno-Altaysk */ + "altai standard time", "Altai Daylight Time", + "Asia/Barnaul" + }, + { + /* (UTC+03:00) Kuwait, Riyadh */ + "arab standard time", "Arab Daylight Time", + "Asia/Riyadh" + }, + { + /* (UTC+04:00) Abu Dhabi, Muscat */ + "arabian standard time", "Arabian Daylight Time", + "Asia/Dubai" + }, + { + /* (UTC+03:00) Baghdad */ + "arabic standard time", "Arabic Daylight Time", + "Asia/Baghdad" + }, + { + /* (UTC-03:00) City of Buenos Aires */ + "argentina standard time", "Argentina Daylight Time", + "America/Buenos_Aires" + }, + { + /* (UTC+04:00) Astrakhan, Ulyanovsk */ + "astrakhan standard time", "Astrakhan Daylight Time", + "Europe/Astrakhan" + }, + { + /* (UTC-04:00) Atlantic Time (Canada) */ + "atlantic standard time", "Atlantic Daylight Time", + "America/Halifax" + }, + { + /* (UTC+09:30) Darwin */ + "aus central standard time", "AUS Central Daylight Time", + "Australia/Darwin" + }, + { + /* (UTC+08:45) Eucla */ + "aus central w. standard time", "Aus Central W. Daylight Time", + "Australia/Eucla" + }, + { + /* (UTC+10:00) Canberra, Melbourne, Sydney */ + "aus eastern standard time", "AUS Eastern Daylight Time", + "Australia/Sydney" + }, + { + /* (UTC+04:00) Baku */ + "azerbaijan standard time", "Azerbaijan Daylight Time", + "Asia/Baku" + }, + { + /* (UTC-01:00) Azores */ + "azores standard time", "Azores Daylight Time", + "Atlantic/Azores" + }, + { + /* (UTC-03:00) Salvador */ + "bahia standard time", "Bahia Daylight Time", + "America/Bahia" + }, + { + /* (UTC+06:00) Dhaka */ + "bangladesh standard time", "Bangladesh Daylight Time", + "Asia/Dhaka" + }, + { + /* (UTC+03:00) Minsk */ + "belarus standard time", "Belarus Daylight Time", + "Europe/Minsk" + }, + { + /* (UTC+11:00) Bougainville Island */ + "bougainville standard time", "Bougainville Daylight Time", + "Pacific/Bougainville" + }, + { + /* (UTC-06:00) Saskatchewan */ + "canada central standard time", "Canada Central Daylight Time", + "America/Regina" + }, + { + /* (UTC-01:00) Cape Verde Is. */ + "cape verde standard time", "Cape Verde Daylight Time", + "Atlantic/Cape_Verde" + }, + { + /* (UTC+04:00) Yerevan */ + "caucasus standard time", "Caucasus Daylight Time", + "Asia/Yerevan" + }, + { + /* (UTC+09:30) Adelaide */ + "cen. australia standard time", "Cen. Australia Daylight Time", + "Australia/Adelaide" + }, + { + /* (UTC-06:00) Central America */ + "central america standard time", "Central America Daylight Time", + "America/Guatemala" + }, + { + /* (UTC+06:00) Astana */ + "central asia standard time", "Central Asia Daylight Time", + "Asia/Almaty" + }, + { + /* (UTC-04:00) Cuiaba */ + "central brazilian standard time", "Central Brazilian Daylight Time", + "America/Cuiaba" + }, + { + /* (UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */ + "central europe standard time", "Central Europe Daylight Time", + "Europe/Budapest" + }, + { + /* (UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb */ + "central european standard time", "Central European Daylight Time", + "Europe/Warsaw" + }, + { + /* (UTC+11:00) Solomon Is., New Caledonia */ + "central pacific standard time", "Central Pacific Daylight Time", + "Pacific/Guadalcanal" + }, + { + /* (UTC-06:00) Central Time (US & Canada) */ + "central standard time", "Central Daylight Time", + "America/Chicago" + }, + { + /* (UTC-06:00) Guadalajara, Mexico City, Monterrey */ + "central standard time (mexico)", "Central Daylight Time (Mexico)", + "America/Mexico_City" + }, + { + /* (UTC+12:45) Chatham Islands */ + "chatham islands standard time", "Chatham Islands Daylight Time", + "Pacific/Chatham" + }, + { + /* (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi */ + "china standard time", "China Daylight Time", + "Asia/Shanghai" + }, + { + /* (UTC-05:00) Havana */ + "Cuba standard time", "Cuba Daylight Time", + "America/Havana" + }, + { + /* (UTC-12:00) International Date Line West */ + "dateline standard time", "Dateline Daylight Time", + "Etc/GMT+12" + }, + { + /* (UTC+03:00) Nairobi */ + "e. africa standard time", "E. Africa Daylight Time", + "Africa/Nairobi" + }, + { + /* (UTC+10:00) Brisbane */ + "e. australia standard time", "E. Australia Daylight Time", + "Australia/Brisbane" + }, + { + /* (UTC+02:00) Chisinau */ + "e. europe standard time", "E. Europe Daylight Time", + "Europe/Chisinau" + }, + { + /* (UTC-03:00) Brasilia */ + "e. south america standard time", "E. South America Daylight Time", + "America/Sao_Paulo" + }, + { + /* (UTC-06:00) Easter Island */ + "easter island standard time", "Easter Island Daylight Time", + "Pacific/Easter" + }, + { + /* (UTC-05:00) Eastern Time (US & Canada) */ + "eastern standard time", "Eastern Daylight Time", + "America/New_York" + }, + { + /* (UTC-05:00) Chetumal */ + "eastern standard time (mexico)", "Eastern Daylight Time (Mexico)", + "America/Cancun" + }, + { + /* (UTC+02:00) Cairo */ + "egypt standard time", "Egypt Daylight Time", + "Africa/Cairo" + }, + { + /* (UTC+05:00) Ekaterinburg */ + "ekaterinburg standard time", "Ekaterinburg Daylight Time", + "Asia/Yekaterinburg" + }, + { + /* (UTC+12:00) Fiji */ + "fiji standard time", "Fiji Daylight Time", + "Pacific/Fiji" + }, + { + /* (UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */ + "fle standard time", "FLE Daylight Time", + "Europe/Kiev" + }, + { + /* (UTC+04:00) Tbilisi */ + "georgian standard time", "Georgian Daylight Time", + "Asia/Tbilisi" + }, + { + /* (UTC+00:00) Dublin, Edinburgh, Lisbon, London */ + "gmt standard time", "GMT Daylight Time", + "Europe/London" + }, + { + /* (UTC-03:00) Greenland */ + "greenland standard time", "Greenland Daylight Time", + "America/Godthab" + }, + { + /* + * Windows uses this zone name in various places that lie near the + * prime meridian, but are not in the UK. However, most people + * probably think that "Greenwich" means UK civil time, or maybe even + * straight-up UTC. Atlantic/Reykjavik is a decent match for that + * interpretation because Iceland hasn't observed DST since 1968. + */ + /* (UTC+00:00) Monrovia, Reykjavik */ + "greenwich standard time", "Greenwich Daylight Time", + "Atlantic/Reykjavik" + }, + { + /* (UTC+02:00) Athens, Bucharest */ + "gtb standard time", "GTB Daylight Time", + "Europe/Bucharest" + }, + { + /* (UTC-05:00) Haiti */ + "haiti standard time", "Haiti Daylight Time", + "America/Port-au-Prince" + }, + { + /* (UTC-10:00) Hawaii */ + "hawaiian standard time", "Hawaiian Daylight Time", + "Pacific/Honolulu" + }, + { + /* (UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi */ + "india standard time", "India Daylight Time", + "Asia/Calcutta" + }, + { + /* (UTC+03:30) Tehran */ + "iran standard time", "Iran Daylight Time", + "Asia/Tehran" + }, + { + /* (UTC+02:00) Jerusalem */ + "israel standard time", "Israel Daylight Time", + "Asia/Jerusalem" + }, + { + /* (UTC+02:00) Amman */ + "jordan standard time", "Jordan Daylight Time", + "Asia/Amman" + }, + { + /* (UTC+02:00) Kaliningrad */ + "kaliningrad standard time", "Kaliningrad Daylight Time", + "Europe/Kaliningrad" + }, + { + /* (UTC+12:00) Petropavlovsk-Kamchatsky - Old */ + "kamchatka standard time", "Kamchatka Daylight Time", + "Asia/Kamchatka" + }, + { + /* (UTC+09:00) Seoul */ + "korea standard time", "Korea Daylight Time", + "Asia/Seoul" + }, + { + /* (UTC+02:00) Tripoli */ + "libya standard time", "Libya Daylight Time", + "Africa/Tripoli" + }, + { + /* (UTC+14:00) Kiritimati Island */ + "line islands standard time", "Line Islands Daylight Time", + "Pacific/Kiritimati" + }, + { + /* (UTC+10:30) Lord Howe Island */ + "lord howe standard time", "Lord Howe Daylight Time", + "Australia/Lord_Howe" + }, + { + /* (UTC+11:00) Magadan */ + "magadan standard time", "Magadan Daylight Time", + "Asia/Magadan" + }, + { + /* (UTC-03:00) Punta Arenas */ + "magallanes standard time", "Magallanes Daylight Time", + "America/Punta_Arenas" + }, + { + /* (UTC-09:30) Marquesas Islands */ + "marquesas standard time", "Marquesas Daylight Time", + "Pacific/Marquesas" + }, + { + /* (UTC+04:00) Port Louis */ + "mauritius standard time", "Mauritius Daylight Time", + "Indian/Mauritius" + }, + { + /* (UTC-02:00) Mid-Atlantic - Old */ + "mid-atlantic standard time", "Mid-Atlantic Daylight Time", + "Atlantic/South_Georgia" + }, + { + /* (UTC+02:00) Beirut */ + "middle east standard time", "Middle East Daylight Time", + "Asia/Beirut" + }, + { + /* (UTC-03:00) Montevideo */ + "montevideo standard time", "Montevideo Daylight Time", + "America/Montevideo" + }, + { + /* (UTC+01:00) Casablanca */ + "morocco standard time", "Morocco Daylight Time", + "Africa/Casablanca" + }, + { + /* (UTC-07:00) Mountain Time (US & Canada) */ + "mountain standard time", "Mountain Daylight Time", + "America/Denver" + }, + { + /* (UTC-07:00) Chihuahua, La Paz, Mazatlan */ + "mountain standard time (mexico)", "Mountain Daylight Time (Mexico)", + "America/Chihuahua" + }, + { + /* (UTC+06:30) Yangon (Rangoon) */ + "myanmar standard time", "Myanmar Daylight Time", + "Asia/Rangoon" + }, + { + /* (UTC+07:00) Novosibirsk */ + "n. central asia standard time", "N. Central Asia Daylight Time", + "Asia/Novosibirsk" + }, + { + /* (UTC+02:00) Windhoek */ + "namibia standard time", "Namibia Daylight Time", + "Africa/Windhoek" + }, + { + /* (UTC+05:45) Kathmandu */ + "nepal standard time", "Nepal Daylight Time", + "Asia/Katmandu" + }, + { + /* (UTC+12:00) Auckland, Wellington */ + "new zealand standard time", "New Zealand Daylight Time", + "Pacific/Auckland" + }, + { + /* (UTC-03:30) Newfoundland */ + "newfoundland standard time", "Newfoundland Daylight Time", + "America/St_Johns" + }, + { + /* (UTC+11:00) Norfolk Island */ + "norfolk standard time", "Norfolk Daylight Time", + "Pacific/Norfolk" + }, + { + /* (UTC+08:00) Irkutsk */ + "north asia east standard time", "North Asia East Daylight Time", + "Asia/Irkutsk" + }, + { + /* (UTC+07:00) Krasnoyarsk */ + "north asia standard time", "North Asia Daylight Time", + "Asia/Krasnoyarsk" + }, + { + /* (UTC+09:00) Pyongyang */ + "north korea standard time", "North Korea Daylight Time", + "Asia/Pyongyang" + }, + { + /* (UTC+06:00) Omsk */ + "omsk standard time", "Omsk Daylight Time", + "Asia/Omsk" + }, + { + /* (UTC-04:00) Santiago */ + "pacific sa standard time", "Pacific SA Daylight Time", + "America/Santiago" + }, + { + /* (UTC-08:00) Pacific Time (US & Canada) */ + "pacific standard time", "Pacific Daylight Time", + "America/Los_Angeles" + }, + { + /* (UTC-08:00) Baja California */ + "pacific standard time (mexico)", "Pacific Daylight Time (Mexico)", + "America/Tijuana" + }, + { + /* (UTC+05:00) Islamabad, Karachi */ + "pakistan standard time", "Pakistan Daylight Time", + "Asia/Karachi" + }, + { + /* (UTC-04:00) Asuncion */ + "paraguay standard time", "Paraguay Daylight Time", + "America/Asuncion" + }, + { + /* (UTC+05:00) Qyzylorda */ + "qyzylorda standard time", "Qyzylorda Daylight Time", + "Asia/Qyzylorda" + }, + { + /* (UTC+01:00) Brussels, Copenhagen, Madrid, Paris */ + "romance standard time", "Romance Daylight Time", + "Europe/Paris" + }, + { + /* (UTC+04:00) Izhevsk, Samara */ + "russia time zone 3", "Russia time zone 3", + "Europe/Samara" + }, + { + /* (UTC+11:00) Chokurdakh */ + "russia time zone 10", "Russia time zone 10", + "Asia/Srednekolymsk" + }, + { + /* (UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky */ + "russia time zone 11", "Russia time zone 11", + "Asia/Kamchatka" + }, + { + /* (UTC+03:00) Moscow, St. Petersburg */ + "Russian standard time", "Russian Daylight Time", + "Europe/Moscow" + }, + { + /* (UTC-03:00) Cayenne, Fortaleza */ + "sa eastern standard time", "SA Eastern Daylight Time", + "America/Cayenne" + }, + { + /* (UTC-05:00) Bogota, Lima, Quito, Rio Branco */ + "sa pacific standard time", "SA Pacific Daylight Time", + "America/Bogota" + }, + { + /* (UTC-04:00) Georgetown, La Paz, Manaus, San Juan */ + "sa western standard time", "SA Western Daylight Time", + "America/La_Paz" + }, + { + /* (UTC-03:00) Saint Pierre and Miquelon */ + "saint pierre standard time", "Saint Pierre Daylight Time", + "America/Miquelon" + }, + { + /* (UTC+11:00) Sakhalin */ + "sakhalin standard time", "Sakhalin Daylight Time", + "Asia/Sakhalin" + }, + { + /* (UTC+13:00) Samoa */ + "samoa standard time", "Samoa Daylight Time", + "Pacific/Apia" + }, + { + /* (UTC+00:00) Sao Tome */ + "sao tome standard time", "Sao Tome Daylight Time", + "Africa/Sao_Tome" + }, + { + /* (UTC+04:00) Saratov */ + "saratov standard time", "Saratov Daylight Time", + "Europe/Saratov" + }, + { + /* (UTC+07:00) Bangkok, Hanoi, Jakarta */ + "se asia standard time", "SE Asia Daylight Time", + "Asia/Bangkok" + }, + { + /* (UTC+08:00) Kuala Lumpur, Singapore */ + "singapore standard time", "Singapore Daylight Time", + "Asia/Singapore" + }, + { + /* (UTC+02:00) Harare, Pretoria */ + "south africa standard time", "South Africa Daylight Time", + "Africa/Johannesburg" + }, + { + /* (UTC+02:00) Juba */ + "south sudan standard time", "South Sudan Daylight Time", + "Africa/Juba" + }, + { + /* (UTC+05:30) Sri Jayawardenepura */ + "sri Lanka standard time", "Sri Lanka Daylight Time", + "Asia/Colombo" + }, + { + /* (UTC+02:00) Khartoum */ + "sudan standard time", "Sudan Daylight Time", + "Africa/Khartoum" + }, + { + /* (UTC+02:00) Damascus */ + "syria standard time", "Syria Daylight Time", + "Asia/Damascus" + }, + { + /* (UTC+08:00) Taipei */ + "taipei standard time", "Taipei Daylight Time", + "Asia/Taipei" + }, + { + /* (UTC+10:00) Hobart */ + "tasmania standard time", "Tasmania Daylight Time", + "Australia/Hobart" + }, + { + /* (UTC-03:00) Araguaina */ + "tocantins standard time", "Tocantins Daylight Time", + "America/Araguaina" + }, + { + /* (UTC+09:00) Osaka, Sapporo, Tokyo */ + "tokyo standard time", "Tokyo Daylight Time", + "Asia/Tokyo" + }, + { + /* (UTC+07:00) Tomsk */ + "tomsk standard time", "Tomsk Daylight Time", + "Asia/Tomsk" + }, + { + /* (UTC+13:00) Nuku'alofa */ + "tonga standard time", "Tonga Daylight Time", + "Pacific/Tongatapu" + }, + { + /* (UTC+09:00) Chita */ + "transbaikal standard time", "Transbaikal Daylight Time", + "Asia/Chita" + }, + { + /* (UTC+03:00) Istanbul */ + "turkey standard time", "Turkey Daylight Time", + "Europe/Istanbul" + }, + { + /* (UTC-05:00) Turks and Caicos */ + "turks and caicos standard time", "Turks And Caicos Daylight Time", + "America/Grand_Turk" + }, + { + /* (UTC+08:00) Ulaanbaatar */ + "ulaanbaatar standard time", "Ulaanbaatar Daylight Time", + "Asia/Ulaanbaatar" + }, + { + /* (UTC-05:00) Indiana (East) */ + "us eastern standard time", "US Eastern Daylight Time", + "America/Indianapolis" + }, + { + /* (UTC-07:00) Arizona */ + "us mountain standard time", "US Mountain Daylight Time", + "America/Phoenix" + }, + { + /* (UTC) Coordinated Universal Time */ + "utc", "UTC", + "UTC" + }, + { + /* (UTC+12:00) Coordinated Universal Time+12 */ + "utc+12", "UTC+12", + "Etc/GMT-12" + }, + { + /* (UTC+13:00) Coordinated Universal Time+13 */ + "utc+13", "UTC+13", + "Etc/GMT-13" + }, + { + /* (UTC-02:00) Coordinated Universal Time-02 */ + "utc-02", "UTC-02", + "Etc/GMT+2" + }, + { + /* (UTC-08:00) Coordinated Universal Time-08 */ + "utc-08", "UTC-08", + "Etc/GMT+8" + }, + { + /* (UTC-09:00) Coordinated Universal Time-09 */ + "utc-09", "UTC-09", + "Etc/GMT+9" + }, + { + /* (UTC-11:00) Coordinated Universal Time-11 */ + "utc-11", "UTC-11", + "Etc/GMT+11" + }, + { + /* (UTC-04:00) Caracas */ + "venezuela standard time", "Venezuela Daylight Time", + "America/Caracas" + }, + { + /* (UTC+10:00) Vladivostok */ + "vladivostok standard time", "Vladivostok Daylight Time", + "Asia/Vladivostok" + }, + { + /* (UTC+04:00) Volgograd */ + "volgograd standard time", "Volgograd Daylight Time", + "Europe/Volgograd" + }, + { + /* (UTC+08:00) Perth */ + "w. australia standard time", "W. Australia Daylight Time", + "Australia/Perth" + }, + { + /* (UTC+01:00) West Central Africa */ + "w. central africa standard time", "W. Central Africa Daylight Time", + "Africa/Lagos" + }, + { + /* (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */ + "w. europe standard time", "W. Europe Daylight Time", + "Europe/Berlin" + }, + { + /* (UTC+07:00) Hovd */ + "w. mongolia standard time", "W. Mongolia Daylight Time", + "Asia/Hovd" + }, + { + /* (UTC+05:00) Ashgabat, Tashkent */ + "west asia standard time", "West Asia Daylight Time", + "Asia/Tashkent" + }, + { + /* (UTC+02:00) Gaza, Hebron */ + "west bank standard time", "West Bank Daylight Time", + "Asia/Hebron" + }, + { + /* (UTC+10:00) Guam, Port Moresby */ + "west pacific standard time", "West Pacific Daylight Time", + "Pacific/Port_Moresby" + }, + { + /* (UTC+09:00) Yakutsk */ + "yakutsk standard time", "Yakutsk Daylight Time", + "Asia/Yakutsk" + }, + { + /* (UTC-07:00) Yukon */ + "yukon standard time", "Yukon Daylight Time", + "America/Whitehorse" + } +}; + +#endif /* TSQL_TIMEZONE_H */ 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/tsqlIface.cpp b/contrib/babelfishpg_tsql/src/tsqlIface.cpp index bceccdcc37..2c0f440db8 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" @@ -84,6 +85,7 @@ extern "C" extern size_t get_num_pg_reserved_keywords_to_be_delimited(); extern char * construct_unique_index_name(char *index_name, char *relation_name); extern bool enable_hint_mapping; + extern bool check_fulltext_exist(const char *schema_name, const char *table_name); extern int escape_hatch_showplan_all; } @@ -109,10 +111,15 @@ PLtsql_stmt *makeCfl(TSqlParser::Cfl_statementContext *ctx, tsqlBuilder &builder PLtsql_stmt *makeSQL(ParserRuleContext *ctx); std::vector makeAnother(TSqlParser::Another_statementContext *ctx, tsqlBuilder &builder); PLtsql_stmt *makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx); +PLtsql_stmt *makeExecuteProcedure(ParserRuleContext *ctx, std::string call_type); PLtsql_stmt *makeInsertBulkStatement(TSqlParser::Dml_statementContext *ctx); +PLtsql_stmt *makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx); PLtsql_stmt *makeSetExplainModeStatement(TSqlParser::Set_statementContext *ctx, bool is_explain_only); PLtsql_expr *makeTsqlExpr(const std::string &fragment, bool addSelect); PLtsql_expr *makeTsqlExpr(ParserRuleContext *ctx, bool addSelect); +PLtsql_stmt *makeCreateFulltextIndexStmt(TSqlParser::Create_fulltext_indexContext *ctx); +PLtsql_stmt *makeDropFulltextIndexStmt(TSqlParser::Drop_fulltext_indexContext *ctx); +std::pair getTableNameAndSchemaName(TSqlParser::Table_nameContext* ctx); void * makeBlockStmt(ParserRuleContext *ctx, tsqlBuilder &builder); void replaceTokenStringFromQuery(PLtsql_expr* expr, TerminalNode* tokenNode, const char* repl, ParserRuleContext *baseCtx); void replaceCtxStringFromQuery(PLtsql_expr* expr, ParserRuleContext *ctx, const char *repl, ParserRuleContext *baseCtx); @@ -121,13 +128,13 @@ void removeCtxStringFromQuery(PLtsql_expr* expr, ParserRuleContext *ctx, ParserR void extractQueryHintsFromOptionClause(TSqlParser::Option_clauseContext *octx); void extractTableHints(TSqlParser::With_table_hintsContext *tctx, std::string table_name); std::string extractTableName(TSqlParser::Ddl_objectContext *ctx, TSqlParser::Table_source_itemContext *tctx); +std::string extractSchemaName(TSqlParser::Ddl_objectContext *ctx, TSqlParser::Table_source_itemContext *tctx); void extractTableHint(TSqlParser::Table_hintContext *table_hint, std::string table_name); void extractJoinHint(TSqlParser::Join_hintContext *join_hint, std::string table_name1, std::string table_names); void extractJoinHintFromOption(TSqlParser::OptionContext *option); std::string extractIndexValues(std::vector index_valuesCtx, std::string table_name); static void *makeBatch(TSqlParser::Tsql_fileContext *ctx, tsqlBuilder &builder); -//static void *makeBatch(TSqlParser::Block_statementContext *ctx, tsqlBuilder &builder); static void process_execsql_destination(TSqlParser::Dml_statementContext *ctx, PLtsql_stmt_execsql *stmt); static void process_execsql_remove_unsupported_tokens(TSqlParser::Dml_statementContext *ctx, PLtsql_expr_query_mutator *exprMutator); @@ -136,9 +143,10 @@ static bool post_process_alter_table(TSqlParser::Alter_tableContext *ctx, PLtsql static bool post_process_create_index(TSqlParser::Create_indexContext *ctx, PLtsql_stmt_execsql *stmt, TSqlParser::Ddl_statementContext *baseCtx); static bool post_process_create_database(TSqlParser::Create_databaseContext *ctx, PLtsql_stmt_execsql *stmt, TSqlParser::Ddl_statementContext *baseCtx); static bool post_process_create_type(TSqlParser::Create_typeContext *ctx, PLtsql_stmt_execsql *stmt, TSqlParser::Ddl_statementContext *baseCtx); -static void post_process_table_source(TSqlParser::Table_source_itemContext *ctx, PLtsql_expr *expr, ParserRuleContext *baseCtx); +static void post_process_table_source(TSqlParser::Table_source_itemContext *ctx, PLtsql_expr *expr, ParserRuleContext *baseCtx, bool is_freetext_predicate = false); static void post_process_declare_cursor_statement(PLtsql_stmt_decl_cursor *stmt, TSqlParser::Declare_cursorContext *ctx, tsqlBuilder &builder); static void post_process_declare_table_statement(PLtsql_stmt_decl_table *stmt, TSqlParser::Table_type_definitionContext *ctx); +static bool check_freetext_predicate(TSqlParser::Search_conditionContext *ctx); static PLtsql_var *lookup_cursor_variable(const char *varname); static PLtsql_var *build_cursor_variable(const char *curname, int lineno); static int read_extended_cursor_option(TSqlParser::Declare_cursor_optionsContext *ctx, int current_cursor_option); @@ -169,9 +177,15 @@ template static std::string rewrite_column_name_with_omitted_schema_na static bool does_object_name_need_delimiter(TSqlParser::IdContext *id); static std::string delimit_identifier(TSqlParser::IdContext *id); static bool does_msg_exceeds_params_limit(const std::string& msg); -static std::string getProcNameFromExecParam(TSqlParser::Execute_parameterContext *exParamCtx); static std::string getIDName(TerminalNode *dq, TerminalNode *sb, TerminalNode *id); static ANTLR_result antlr_parse_query(const char *sourceText, bool useSSLParsing); +std::string rewriteDoubleQuotedString(const std::string strDoubleQuoted); +std::string escapeDoubleQuotes(const std::string strWithDoubleQuote); +static bool in_execute_body_batch = false; +static bool in_execute_body_batch_parameter = false; +static const std::string fragment_SELECT_prefix = "SELECT "; // fragment prefix for expressions +static const std::string fragment_EXEC_prefix = "EXEC "; // fragment prefix for execute_body_batch +static PLtsql_stmt *makeChangeDbOwnerStatement(TSqlParser::Alter_authorizationContext *ctx); /* * Structure / Utility function for general purpose of query string modification @@ -243,6 +257,7 @@ static std::string validate_and_stringify_hints(); static int find_hint_offset(const char * queryTxt); static bool pltsql_parseonly = false; +bool has_identity_function = false; static void breakHere() @@ -397,6 +412,25 @@ std::pair getLineAndPos(TerminalNode *node) static ParseTreeProperty fragments; +// Keeps track of location of expressions being rewritten into a fragment 'SELECT ' +static std::map>> selectFragmentOffsets; + +// Record the offsets for a 'SELECT ' fragment +void +recordSelectFragmentOffsets(ParseTree *ctx, int ixStart, int ixEnd, int ixShift) +{ + Assert(ctx); + selectFragmentOffsets.emplace(std::make_pair(ctx, std::make_pair(ixStart, std::make_pair(ixEnd, ixShift)))); +} + +void +recordSelectFragmentOffsets(ParseTree *ctx, ParserRuleContext *expr) +{ + Assert(ctx); + Assert(expr); + recordSelectFragmentOffsets(ctx, expr->getStart()->getStartIndex(), expr->getStop()->getStopIndex(), 0); +} + void attachPLtsql_fragment(ParseTree *node, PLtsql_stmt *fragment) { @@ -499,6 +533,7 @@ class PLtsql_expr_query_mutator PLtsql_expr_query_mutator(PLtsql_expr *expr, ParserRuleContext* baseCtx); void add(int antlr_pos, std::string orig_text, std::string repl_text); + void markSelectFragment(ParserRuleContext *ctx); void run(); @@ -508,8 +543,15 @@ class PLtsql_expr_query_mutator protected: // intentionally use std::map to iterate it via sorted order. std::map> m; // pos -> (orig_text, repl_text) - - int base_idx; + + int base_idx; + + // Indicate the fragment being processed is an expression that was prefixed with 'SELECT ', + // so that offsets can be adjusted when doing the rewriting + bool isSelectFragment = false; + int idxStart = 0; + int idxEnd = 0; + int idxStartShift = 0; }; PLtsql_expr_query_mutator::PLtsql_expr_query_mutator(PLtsql_expr *e, ParserRuleContext* baseCtx) @@ -521,20 +563,61 @@ PLtsql_expr_query_mutator::PLtsql_expr_query_mutator(PLtsql_expr *e, ParserRuleC throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. NULL expression", getLineAndPos(baseCtx)); size_t base_index = baseCtx->getStart()->getStartIndex(); + if (base_index == INVALID_INDEX) throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. base index is invalid", getLineAndPos(baseCtx)); base_idx = base_index; + isSelectFragment = false; +} + +void PLtsql_expr_query_mutator::markSelectFragment(ParserRuleContext *ctx) +{ + Assert(ctx); + Assert(selectFragmentOffsets.count(ctx) > 0); + + auto p = selectFragmentOffsets.at(ctx); + + isSelectFragment = true; + idxStart = p.first; + idxEnd = p.second.first; + idxStartShift = p.second.second; } void PLtsql_expr_query_mutator::add(int antlr_pos, std::string orig_text, std::string repl_text) { int offset = antlr_pos - base_idx; + + if (isSelectFragment) + { + // For SELECT fragments, only apply the item when antlr_pos is between idxStart and idxEnd: + // when there are multiple expressions per statement (only for DECLARE), the rewrites must be + // applied to the correct expression + if ((antlr_pos < idxStart) || (antlr_pos > idxEnd)) + { + return; + } - /* validation check */ - if (offset < 0) - throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is negative", 0, 0); - if (offset > (int)strlen(expr->query)) - throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is too large", 0, 0); + // Adjust offset to reflect the fact that the expression in the fragment is now prefixed with only 'SELECT ' + offset = antlr_pos - idxStart; + + // Adjust offset once more if the expression was shifted left (for a compound SET @v operator) + if (idxStartShift > 0) + { + offset = offset + idxStartShift; + } + } + + if ((orig_text.front() == '"') && (orig_text.back() == '"') && (repl_text.front() == '\'') && (repl_text.back() == '\'')) + { + // Do not validate the positions of strings as these are not replaced by their positions + } + else { + /* validation check */ + if (offset < 0) + throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is negative", 0, 0); + if (offset > (int)strlen(expr->query)) + throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. offset value is too large", 0, 0); + } m.emplace(std::make_pair(offset, std::make_pair(orig_text, repl_text))); } @@ -547,19 +630,23 @@ void PLtsql_expr_query_mutator::run() * To rewrite query based on token position, we have to convert a query string to std::u32string first * so that offset should indicate a correct position to be replaced. */ + if (m.size() == 0) return; // nothing to do + std::u32string query = utf8_to_utf32(expr->query); std::u32string rewritten_query; - + size_t cursor = 0; // cursor to expr->query where next copy should start for (const auto &entry : m) - { + { size_t offset = entry.first; const std::u32string& orig_text = utf8_to_utf32(entry.second.first.c_str()); const std::u32string& repl_text = utf8_to_utf32(entry.second.second.c_str()); + if (isSelectFragment) offset += fragment_SELECT_prefix.length(); // because this is an expression prefixed with 'SELECT ' + if (orig_text.length() == 0 || orig_text.c_str(), query.substr(offset, orig_text.length()) == orig_text) // local_id maybe already deleted in some cases such as select-assignment. check here if it still exists) { if (offset - cursor < 0) - throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. might be due to mulitiple mutation on the same position", 0, 0); + throw PGErrorWrapperException(ERROR, ERRCODE_INTERNAL_ERROR, "can't mutate an internal query. might be due to multiple mutations on the same position", 0, 0); if (offset - cursor > 0) // if offset==cursor, no need to copy rewritten_query += query.substr(cursor, offset - cursor); // copy substring of expr->query. ranged [cursor, offset) rewritten_query += repl_text; @@ -568,8 +655,8 @@ void PLtsql_expr_query_mutator::run() } if (cursor < strlen(expr->query)) rewritten_query += query.substr(cursor); // copy remaining expr->query - - // update query string with quoted one + + // update query string std::string new_query = antlrcpp::utf32_to_utf8(rewritten_query); expr->query = pstrdup(new_query.c_str()); } @@ -599,37 +686,6 @@ add_query_hints(PLtsql_expr_query_mutator *mutator, int contextOffset) mutator->add(contextOffset + initialTokenOffset, "", hint); } -// Try to retrieve the procedure name as in execute_body/execute_body_batch -// from the context of execute_parameter. -static std::string getProcNameFromExecParam(TSqlParser::Execute_parameterContext *exParamCtx) -{ - antlr4::tree::ParseTree *ctx = exParamCtx; - // We only need to loop max number of dereferences needed from the context - // of execute_parameter to execute_body/execute_body_batch. - // Currently that number is 3 + (number of execute_statement_arg_unnamed - 1). - // Because for now we only need this function for sp_tables which have - // at most 5 parameters, 8 seems to be good enough here. - int cnt = 8; - - while (ctx->parent != nullptr && cnt-- > 0) - { - TSqlParser::Execute_bodyContext * exBodyCtx = dynamic_cast(ctx->parent); - TSqlParser::Execute_body_batchContext *exBodyBatchCtx = dynamic_cast(ctx->parent); - TSqlParser::IdContext *proc = nullptr; - - if (exBodyCtx != nullptr && exBodyCtx->proc_var == nullptr) - proc = exBodyCtx->func_proc_name_server_database_schema()->procedure; - else if (exBodyBatchCtx != nullptr) - proc = exBodyBatchCtx->func_proc_name_server_database_schema()->procedure; - - if (proc != nullptr) - return stripQuoteFromId(proc); - - ctx = ctx->parent; - } - return ""; -} - static std::string validate_and_stringify_hints() { @@ -713,8 +769,8 @@ clear_tables_info() * (please see the comment on rewritten_query_fragment). * tsqlSelectMuator was introduced to cover corner cases such as CREATE-VIEW and DECLARE-CURSOR * which need to deal with inner SELECT statement. - * tsqlCommonMutator was added to cover a rewriting logic which needs to be apllied in - * batch-level statment and normal statment. + * tsqlCommonMutator was added to cover a rewriting logic which needs to be applied in + * batch-level statement and normal statement. * * TODO: * The plan is to incorporate all rewriting logics to tsqlCommonMutator. Other @@ -730,6 +786,71 @@ 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); + } + 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 { + 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); + } + + } + } + } + + 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); + } + } + + void enterKill_statement(TSqlParser::Kill_statementContext *ctx) override { + if (in_create_or_alter_function){ + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "Invalid use of a side-effecting operator 'KILL' within a function.", 0, 0); + } + } /* Column Name */ void exitSimple_column_name(TSqlParser::Simple_column_nameContext *ctx) override @@ -774,18 +895,54 @@ 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; + + if (obj_server->keyword()) + server_name_str = getFullText(obj_server->keyword()); + else + 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_internal('server_name', 'SELECT * FROM db_name.schema_name.obj_name') + */ + std::string str = std::string("openquery_internal(") + 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 @@ -854,6 +1011,16 @@ class tsqlCommonMutator : public TSqlParserBaseListener // don't need to call does_object_name_need_delimiter() because problematic keywords are already allowed as function name } + void enterExecute_body_batch(TSqlParser::Execute_body_batchContext *ctx) override + { + in_execute_body_batch = true; + } + + void exitExecute_body_batch(TSqlParser::Execute_body_batchContext *ctx) override + { + in_execute_body_batch = false; + } + void exitFunc_proc_name_server_database_schema(TSqlParser::Func_proc_name_server_database_schemaContext *ctx) override { GetCtxFunc getDatabase = [](TSqlParser::Func_proc_name_server_database_schemaContext *o) { return o->database; }; @@ -861,9 +1028,14 @@ class tsqlCommonMutator : public TSqlParserBaseListener 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))); + { + int EXEC_prepend_length = (in_execute_body_batch) ? fragment_EXEC_prefix.length() : 0; // add length of prefix prepended internally for execute_body_batch + rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex()+EXEC_prepend_length, 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))); + } // don't need to call does_object_name_need_delimiter() because problematic keywords are already allowed as function name } @@ -908,13 +1080,20 @@ class tsqlCommonMutator : public TSqlParserBaseListener * * Since we have implemented OPENQUERY as a PG function, the linked_server gets * interpreted as a column. To fix this, we enclose the linked_server in single - * quotes, so that the function now gets called as OPENQUERY('linked_server', 'query') + * quotes, so that the function now gets called as openquery_internal('linked_server', 'query') */ if (linked_srv) { - std::string linked_srv_name = getIDName(linked_srv->DOUBLE_QUOTE_ID(), linked_srv->SQUARE_BRACKET_ID(), linked_srv->ID()); + std::string linked_srv_name; + + if (linked_srv->keyword()) + linked_srv_name = getFullText(linked_srv->keyword()); + else + linked_srv_name = getIDName(linked_srv->DOUBLE_QUOTE_ID(), linked_srv->SQUARE_BRACKET_ID(), linked_srv->ID()); + std::string str = std::string("'") + linked_srv_name + std::string("'"); + rewritten_query_fragment.emplace(std::make_pair(ctx->OPENQUERY()->getSymbol()->getStartIndex(), std::make_pair(::getFullText(ctx->OPENQUERY()), "openquery_internal"))); rewritten_query_fragment.emplace(std::make_pair(linked_srv->start->getStartIndex(), std::make_pair(linked_srv_name, str))); } } @@ -932,9 +1111,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 +1139,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); @@ -990,8 +1192,8 @@ class tsqlBuilder : public tsqlCommonMutator std::string schema_name; std::string db_name; bool is_function = false; - bool is_schema_specified = false; - + bool is_schema_specified = false; + // We keep a stack of the containers that are active during a traversal. // A container will correspond to a block or a batch - these are containers // because they contain a list of the PLtsql_stmt structures. @@ -1098,7 +1300,7 @@ class tsqlBuilder : public tsqlCommonMutator std::string desc{getNodeDesc(ctx)}; if (pltsql_enable_antlr_detailed_log) - std::cout << "+entering " << (void *) ctx << "[" << desc << "]" << std::endl; + std::cout << "+entering (tsqlBuilder)" << (void *) ctx << "[" << desc << "]" << std::endl; } void exitEveryRule(ParserRuleContext *ctx) override @@ -1106,7 +1308,7 @@ class tsqlBuilder : public tsqlCommonMutator std::string desc{getNodeDesc(ctx)}; if (pltsql_enable_antlr_detailed_log) - std::cout << "-leaving " << (void *) ctx << "[" << desc << "]" << std::endl; + std::cout << "-leaving (tsqlBuilder)" << (void *) ctx << "[" << desc << "]" << std::endl; } void graft(PLtsql_stmt *stmt, ParserRuleContext *container) @@ -1314,7 +1516,7 @@ class tsqlBuilder : public tsqlCommonMutator void exitCreate_or_alter_procedure(TSqlParser::Create_or_alter_procedureContext *ctx) override { // just throw away all PLtsql_stmt in the container. - // procedure body is a sequenece of sql_clauses. In create-procedure, we don't need to genereate PLtsql_stmt. + // procedure body is a sequence of sql_clauses. In create-procedure, we don't need to generate PLtsql_stmt. // // TODO: Ideally, we may stop visiting or disable vistior logic inside the procedure body. It will save the resoruce. @@ -1343,6 +1545,62 @@ class tsqlBuilder : public tsqlCommonMutator popContainer(ctx); } + void exitAlter_table(TSqlParser::Alter_tableContext *ctx) override + { + if (ctx->TRIGGER() && ctx->id().size() > 1) /* condition to filter alter table statements which contains TRIGGER keyword and multiple trigger names */ + { + /* + * When we come across a alter table query which enable/disable trigger with multiple trigger name, + * we will replace it with list of alter table statements, a statement for each trigger. + * As Postgres only support enabling/disabling of only one trigger using alter table syntax, so a call like: + * + * ALTER TABLE Employees { ENABLE | DISABLE } TRIGGER trigger_a, trigger_b + * GO + * + * will be re-written as: + * + * ALTER TABLE Employees { ENABLE | DISABLE } TRIGGER trigger_a; + * ALTER TABLE Employees { ENABLE | DISABLE } TRIGGER trigger_b; + */ + + std::vector list_id = ctx->id(); + TSqlParser::Table_nameContext *table_name = ctx->tabname; + + std::string str = std::string(""); + std::string action_type; + if (ctx->ENABLE() != nullptr) + { + action_type = std::string(" ENABLE"); + } + else + { + action_type = std::string(" DISABLE"); + } + + for (TSqlParser::IdContext *id : list_id) { + str += std::string("ALTER TABLE ") + ::getFullText(table_name) + action_type + std::string(" TRIGGER ") + ::getFullText(id) + "; "; + } + + rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(::getFullText(ctx), str))); + } + } + + void exitEnable_trigger(TSqlParser::Enable_triggerContext *ctx) override + { + if(ctx->SERVER() || ctx->DATABASE()) + { + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'DDL trigger' is not currently supported in Babelfish.", 0, 0); + } + } + + void exitDisable_trigger(TSqlParser::Disable_triggerContext *ctx) override + { + if(ctx->SERVER() || ctx->DATABASE()) + { + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'DDL trigger' is not currently supported in Babelfish.", 0, 0); + } + } + ////////////////////////////////////////////////////////////////////////////// // Non-container statement management ////////////////////////////////////////////////////////////////////////////// @@ -1426,7 +1684,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()) @@ -1437,9 +1695,11 @@ class tsqlBuilder : public tsqlCommonMutator else if (ddl_object && !ddl_object->local_id()) /* insert into non-local object */ throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "'INSERT' cannot be used within a function", getLineAndPos(ddl_object)); } - else if (ctx->update_statement() && ctx->update_statement()->ddl_object() && !ctx->update_statement()->ddl_object()->local_id()) /* update non-local object */ + else if (ctx->update_statement() && ctx->update_statement()->ddl_object() && !ctx->update_statement()->ddl_object()->local_id() && + (ctx->update_statement()->table_sources() ? ::getFullText(ctx->update_statement()->table_sources()).c_str()[0] != '@' : true)) /* update non-local object, table variables are allowed */ throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "'UPDATE' cannot be used within a function", getLineAndPos(ctx->update_statement()->ddl_object())); - else if (ctx->delete_statement() && ctx->delete_statement()->delete_statement_from()->ddl_object() && !ctx->delete_statement()->delete_statement_from()->ddl_object()->local_id()) /* delete from non-local object */ + else if (ctx->delete_statement() && ctx->delete_statement()->delete_statement_from()->ddl_object() && !ctx->delete_statement()->delete_statement_from()->ddl_object()->local_id() && + (ctx->delete_statement()->table_sources() ? ::getFullText(ctx->delete_statement()->table_sources()).c_str()[0] != '@' : true)) /* delete non-local object, table variables are allowed */ throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "'DELETE' cannot be used within a function", getLineAndPos(ctx->delete_statement()->delete_statement_from()->ddl_object())); } @@ -1482,14 +1742,45 @@ class tsqlBuilder : public tsqlCommonMutator void enterDdl_statement(TSqlParser::Ddl_statementContext *ctx) override { // See the comments in enterDml_statement() for an explanation of this code - graft(makeSQL(ctx), peekContainer()); - - // clean up object_name positions maps before entering - rewritten_query_fragment.clear(); + PLtsql_stmt *stmt; + if (ctx->alter_authorization()) + { + stmt = makeChangeDbOwnerStatement(ctx->alter_authorization()); + } + else if (ctx->create_fulltext_index()) + { + stmt = makeCreateFulltextIndexStmt(ctx->create_fulltext_index()); + } + else if (ctx->drop_fulltext_index()) + { + stmt = makeDropFulltextIndexStmt(ctx->drop_fulltext_index()); + } + else + { + stmt = makeSQL(ctx); + } + graft(stmt, peekContainer()); + clear_rewritten_query_fragment(); } void exitDdl_statement(TSqlParser::Ddl_statementContext *ctx) override { + if (ctx->alter_authorization()) + { + // Exit in case of Change DB owner + return; + } + + if (ctx->create_fulltext_index()) + { + clear_rewritten_query_fragment(); + return; + } + if (ctx->drop_fulltext_index()) + { + clear_rewritten_query_fragment(); + return; + } PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); Assert(stmt); // record that the stmt is ddl @@ -1497,7 +1788,7 @@ class tsqlBuilder : public tsqlCommonMutator if (is_compiling_create_function()) { - /* T-SQL doens't allow side-effecting operations in CREATE FUNCTION */ + /* T-SQL doesn't allow side-effecting operations in CREATE FUNCTION */ throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_FUNCTION_DEFINITION, "DDL cannot be used within a function", getLineAndPos(ctx)); } @@ -1513,13 +1804,11 @@ class tsqlBuilder : public tsqlCommonMutator nop = post_process_create_database(ctx->create_database(), stmt, ctx); else if (ctx->create_type()) nop = post_process_create_type(ctx->create_type(), stmt, ctx); - else if (ctx->create_fulltext_index() || - ctx->alter_fulltext_index() || - ctx->drop_fulltext_index()) + else if (ctx->alter_fulltext_index()) { ereport(WARNING, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("FULLTEXT related statements will be ignored."))); + errmsg("ALTER FULLTEXT INDEX statement will be ignored."))); nop = true; } @@ -1538,6 +1827,41 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } + void exitCfl_statement(TSqlParser::Cfl_statementContext *ctx) override + { + PLtsql_expr *expr = nullptr; + if (ctx->print_statement()) + { + PLtsql_stmt_print *stmt = (PLtsql_stmt_print *) getPLtsql_fragment(ctx); + expr = (PLtsql_expr *) linitial(stmt->exprs); + } + else if (ctx->raiseerror_statement() && ctx->raiseerror_statement()->raiseerror_msg() && ctx->raiseerror_statement()->raiseerror_msg()->char_string()) + { + PLtsql_stmt_raiserror *stmt = (PLtsql_stmt_raiserror *) getPLtsql_fragment(ctx); + expr = (PLtsql_expr *) linitial(stmt->params); + } + else if (ctx->return_statement()) + { + if (pltsql_curr_compile && pltsql_curr_compile->fn_prokind != PROKIND_PROCEDURE) + { + PLtsql_stmt_return *stmt = (PLtsql_stmt_return *) getPLtsql_fragment(ctx); + expr = (PLtsql_expr *) stmt->expr; + } + } + if (expr) + { + PLtsql_expr_query_mutator mutator(expr, ctx); + mutator.markSelectFragment(ctx); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + + // remove the offsets for processed fragments + selectFragmentOffsets.clear(); + + clear_rewritten_query_fragment(); + } + } + void exitSecurity_statement(TSqlParser::Security_statementContext *ctx) override { if (ctx->grant_statement() && ctx->grant_statement()->TO() && !ctx->grant_statement()->permission_object() @@ -1566,6 +1890,52 @@ class tsqlBuilder : public tsqlCommonMutator } } } + else if (ctx->grant_statement() && ctx->grant_statement()->ON() && ctx->grant_statement()->permission_object() + && ctx->grant_statement()->permission_object()->object_type() && ctx->grant_statement()->permission_object()->object_type()->SCHEMA()) + { + if (ctx->grant_statement()->TO() && ctx->grant_statement()->principals() && ctx->grant_statement()->permissions()) + { + for (auto perm: ctx->grant_statement()->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE() + || single_perm->EXEC() + || single_perm->SELECT() + || single_perm->INSERT() + || single_perm->UPDATE() + || single_perm->DELETE() + || single_perm->REFERENCES()) + { + clear_rewritten_query_fragment(); + return; + } + } + } + } + + else if (ctx->revoke_statement() && ctx->revoke_statement()->ON() && ctx->revoke_statement()->permission_object() + && ctx->revoke_statement()->permission_object()->object_type() && ctx->revoke_statement()->permission_object()->object_type()->SCHEMA()) + { + if (ctx->revoke_statement()->FROM() && ctx->revoke_statement()->principals() && ctx->revoke_statement()->permissions()) + { + for (auto perm: ctx->revoke_statement()->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE() + || single_perm->EXEC() + || single_perm->SELECT() + || single_perm->INSERT() + || single_perm->UPDATE() + || single_perm->DELETE() + || single_perm->REFERENCES()) + { + clear_rewritten_query_fragment(); + return; + } + } + } + } + PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) getPLtsql_fragment(ctx); Assert(stmt); @@ -1593,9 +1963,9 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } - + void exitAnother_statement(TSqlParser::Another_statementContext *ctx) override - { + { // currently, declare_cursor only need rewriting because it contains select statement if (ctx->cursor_statement() && ctx->cursor_statement()->declare_cursor()) { @@ -1604,16 +1974,16 @@ class tsqlBuilder : public tsqlCommonMutator } // Declare table type statement might need rewriting in column definition list. - if (ctx->declare_statement() && ctx->declare_statement()->table_type_definition()) + else if (ctx->declare_statement() && ctx->declare_statement()->table_type_definition()) { PLtsql_stmt_decl_table *decl_table_stmt = (PLtsql_stmt_decl_table *) getPLtsql_fragment(ctx); post_process_declare_table_statement(decl_table_stmt, ctx->declare_statement()->table_type_definition()); } - if (ctx->execute_statement()) + else if (ctx->execute_statement()) { PLtsql_stmt_exec *stmt = (PLtsql_stmt_exec *) getPLtsql_fragment(ctx); - if (stmt->cmd_type == PLTSQL_STMT_EXEC && stmt->proc_name && pg_strcasecmp("sp_tables", stmt->proc_name) == 0) + if (stmt->cmd_type == PLTSQL_STMT_EXEC) { PLtsql_expr_query_mutator mutator(stmt->expr, ctx); add_rewritten_query_fragment_to_mutator(&mutator); // move information of rewritten_query_fragment to mutator. @@ -1621,48 +1991,134 @@ class tsqlBuilder : public tsqlCommonMutator } } + else if (ctx->set_statement() && ctx->set_statement()->expression()) + { + // There should always be offsets for SET expressions + Assert(selectFragmentOffsets.find(ctx->set_statement()) != selectFragmentOffsets.end()); + + PLtsql_stmt_assign *stmt = (PLtsql_stmt_assign *) getPLtsql_fragment(ctx->set_statement()); + PLtsql_expr_query_mutator mutator(stmt->expr, ctx->set_statement()); + mutator.markSelectFragment(ctx->set_statement()); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + } + + else if (ctx->declare_statement()) + { + if (ctx->declare_statement()->declare_local().size() > 0) + { + // For each assignment to a @variable, a fragment was created (via makeInitializer). + // There can be multiple declarations and assignments in a single DECLARE, and these are processed below. + int i = 0; + for (TSqlParser::Declare_localContext *d : ctx->declare_statement()->declare_local() ) + { + i++; + if (d->expression()) + { + ParserRuleContext *ctx_fragment = (ParserRuleContext *) ctx; + if (selectFragmentOffsets.find(d->expression()) != selectFragmentOffsets.end()) + { + ctx_fragment = d->expression(); + } + + PLtsql_stmt_assign *stmt = (PLtsql_stmt_assign *) getPLtsql_fragment(ctx_fragment); + PLtsql_expr_query_mutator mutator(stmt->expr, ctx_fragment); + mutator.markSelectFragment(ctx_fragment); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + } + } + } + } + + // remove the offsets for processed fragments + selectFragmentOffsets.clear(); + clear_rewritten_query_fragment(); } + void exitChar_string(TSqlParser::Char_stringContext *ctx) override + { + std::string str = getFullText(ctx); + + if (str.front() == 'N') + { + // Temporarily remove the leading 'N' only locally here, to make the assertion on str.front() easy (below) + str.erase(0, 1); + } + + if (str.front() == '"') + { + Assert(str.back() == '"'); + + // Change double-quoted string to single-quoted string: + str = rewriteDoubleQuotedString(str); + size_t startPosition = ctx->start->getStartIndex(); + if (in_execute_body_batch_parameter) startPosition += fragment_EXEC_prefix.length(); // add length of prefix prepended internally for execute_body_batch + rewritten_query_fragment.emplace(std::make_pair(startPosition, std::make_pair(::getFullText(ctx), str))); + } + else + { + // This is a single-quoted string, no further action needed + Assert(str.front() == '\''); + Assert(str.back() == '\''); + } + } + + void enterExecute_parameter(TSqlParser::Execute_parameterContext *ctx) override + { + if (in_execute_body_batch) in_execute_body_batch_parameter = true; + } + void exitExecute_parameter(TSqlParser::Execute_parameterContext *ctx) override { - if (ctx->constant() || ctx->id()) + if (ctx->id()) { - // BABEL-2395, BABEL-3640: embedded single quotes are allowed in procedure parameters. - // in tsqlMutator::enterExecute_parameter, we replace "" with '', and also record the place of "" into - // double_quota_places, then in here, we'll replace all ' into '' if it's inside "" - // we replace " in tsqlMutator::enterExecute_parameter first to pass the syntax validation - // then we'll use the double quota rule to replace "'A'" to '''A''' - if (pg_strcasecmp(getProcNameFromExecParam(ctx).c_str(), "sp_tables") == 0) + // A stored procedure parameter which is parsed as a column name (= identifier) + // is either an unquoted string, a double-quoted string, or a bracketed string. + // For a procedure call parameter, a double-quoted string is interpreted + // as a string even with QUOTED_IDENTIFIER=ON. + std::string str = getFullText(ctx->id()); + size_t startPosition = ctx->id()->start->getStartIndex(); + if (in_execute_body_batch_parameter) startPosition += fragment_EXEC_prefix.length(); // add length of prefix prepended internally for execute_body_batch + + if (str.front() == '"') { - std::string argStr; - if (ctx->constant()) - argStr = getFullText(ctx->constant()); - else if (ctx->id()) - argStr = getFullText(ctx->id()); - - std::string newStr; - if (argStr.size() > 1 && argStr.front() == '\'' && argStr.back() == '\'' - && std::binary_search (double_quota_places.begin(), double_quota_places.end(), parameterIndex)) - { - newStr += '\''; - for (std::string::iterator iter = argStr.begin() + 1; iter != argStr.end() - 1; ++iter) - if (*iter == '\'') - { - newStr += "\'\'"; - } else{ - newStr += *iter; - } - newStr += '\''; - if (ctx->constant()) - rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), - std::make_pair(::getFullText(ctx->constant()), newStr))); - else - rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(getFullText(ctx->id()), newStr))); - } + Assert(str.back() == '"'); + + // Change double-quoted string to single-quoted string + str = rewriteDoubleQuotedString(str); + rewritten_query_fragment.emplace(std::make_pair(startPosition, std::make_pair(getFullText(ctx->id()), str))); + } + else if (str.front() == '\'') + { + // This is a single-quoted string, no further action needed + Assert(str.back() == '\''); } - } - parameterIndex++; + else if (str.front() == '[') + { + // When it's a bracketed identifier, remove the delimiters as T-SQL treats it as a string + Assert(str.back() == ']'); + + // Temporarily turn this into a double-quoted string so that we can handle embedded quotes. + // Since embedded double quotes inside a bracketed identifier are not escaped (as they would be in a + // double-quoted string), escape them first. We cannot just call rewriteDoubeQuotedString() since if we'd + // have two adjacent double quotes, i.e. [a""b], this would then become [a"b] so we'd lose one quote. + str = escapeDoubleQuotes(str); + str = '"' + str.substr(1,str.length()-2) + '"'; + str = rewriteDoubleQuotedString(str); + rewritten_query_fragment.emplace(std::make_pair(startPosition, std::make_pair(getFullText(ctx->id()), str))); + } + else + { + // This is an unquoted string parameter which has been parsed as an identifier(column name). + // Put quotes around it: even though it is an identifier in the ANTLR parse tree, it will be + // parsed as a string by the backend parser + str = "'" + str + "'"; + rewritten_query_fragment.emplace(std::make_pair(startPosition, std::make_pair(getFullText(ctx->id()), str))); + } + } + if (in_execute_body_batch_parameter) in_execute_body_batch_parameter = false; } void enterCfl_statement(TSqlParser::Cfl_statementContext *ctx) override @@ -1679,6 +2135,19 @@ class tsqlBuilder : public tsqlCommonMutator clear_rewritten_query_fragment(); } + void enterDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override + { + if (ctx->CHECKIDENT()) + graft(makeDbccCheckidentStatement(ctx), peekContainer()); + + clear_rewritten_query_fragment(); + } + + void exitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override + { + // TO-DO + } + ////////////////////////////////////////////////////////////////////////////// // Special handling of non-statement context ////////////////////////////////////////////////////////////////////////////// @@ -1700,7 +2169,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; @@ -1708,7 +2177,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); @@ -1743,10 +2212,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()), ""))); @@ -1821,6 +2306,21 @@ class tsqlBuilder : public tsqlCommonMutator } } + + if (ctx->func_proc_name_server_database_schema()->procedure) + { + std::string proc_name = stripQuoteFromId(ctx->func_proc_name_server_database_schema()->procedure); + if (pg_strcasecmp(proc_name.c_str(), "identity") == 0) + { + has_identity_function = true; + } + + if (pg_strcasecmp(proc_name.c_str(), "identity_into_bigint") == 0) + { + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, + format_errmsg("function %s does not exist", proc_name.c_str()), getLineAndPos(ctx)); + } + } } } @@ -1828,8 +2328,18 @@ class tsqlBuilder : public tsqlCommonMutator // statement analysis ////////////////////////////////////////////////////////////////////////////// + void enterQuery_specification(TSqlParser::Query_specificationContext *ctx) override + { + has_identity_function = false; + } + void exitQuery_specification(TSqlParser::Query_specificationContext *ctx) override { + // if select doesnt contains into but it contains identity we should throw error + if(has_identity_function && !ctx->INTO()){ + throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, "The IDENTITY function can only be used when the SELECT statement has an INTO clause.", getLineAndPos(ctx)); + } + has_identity_function = false; if (statementMutator) process_query_specification(ctx, statementMutator.get()); } @@ -1876,8 +2386,53 @@ class tsqlBuilder : public tsqlCommonMutator void enterExecute_body_batch(TSqlParser::Execute_body_batchContext *ctx) override { - graft(makeExecBodyBatch(ctx), peekContainer()); + in_execute_body_batch = true; + PLtsql_stmt *stmt = makeExecBodyBatch(ctx); + attachPLtsql_fragment(ctx, stmt); + graft(stmt, peekContainer()); + clear_rewritten_query_fragment(); + } + + void exitExecute_body_batch(TSqlParser::Execute_body_batchContext *ctx) override + { + in_execute_body_batch = false; + PLtsql_stmt_exec *stmt = (PLtsql_stmt_exec *) getPLtsql_fragment(ctx); + PLtsql_expr_query_mutator mutator(stmt->expr, ctx); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + clear_rewritten_query_fragment(); + } + + PLtsql_expr *rewrite_if_condition(TSqlParser::Search_conditionContext *ctx) + { + PLtsql_expr *expr = makeTsqlExpr(ctx, false); + PLtsql_expr_query_mutator mutator(expr, ctx); + add_rewritten_query_fragment_to_mutator(&mutator); + mutator.run(); + clear_rewritten_query_fragment(); + + /* Now we can prepend SELECT to rewritten search_condition */ + expr->query = strdup((std::string("SELECT ") + std::string(expr->query)).c_str()); + return expr; } + + void exitSearch_condition(TSqlParser::Search_conditionContext *ctx) override + { + if (!ctx->parent || !ctx->parent->parent) + return; + + if (((TSqlParser::Cfl_statementContext *) ctx->parent->parent)->if_statement()) + { + + PLtsql_stmt_if *fragment = (PLtsql_stmt_if *) getPLtsql_fragment(ctx->parent->parent); + fragment->cond = rewrite_if_condition(ctx); + } + else if (((TSqlParser::Cfl_statementContext *) ctx->parent->parent)->while_statement()) + { + PLtsql_stmt_while *fragment = (PLtsql_stmt_while *) getPLtsql_fragment(ctx->parent->parent); + fragment->cond = rewrite_if_condition(ctx); + } + } }; //////////////////////////////////////////////////////////////////////////////// @@ -1893,105 +2448,17 @@ class tsqlMutator : public TSqlParserBaseListener { public: MyInputStream &stream; + bool in_procedure_parameter = false; + bool in_procedure_parameter_id = false; std::vector double_quota_places; - int parameterIndex = 0; explicit tsqlMutator(MyInputStream &s) : stream(s) { } - + public: - void enterConstant(TSqlParser::ConstantContext *ctx) override - { - if (ctx->char_string() && ctx->char_string()->STRING()) - { - std::string str = ctx->char_string()->STRING()->getSymbol()->getText(); - - if (str.front() == 'N') - str.erase(0, 1); - - if (str.front() == '"') - { - Assert(str.front() == '"'); - Assert(str.back() == '"'); - - if (str.find('\'') == std::string::npos) - { - // no embedded single-quotes, just change from "foo" to 'foo' - str.front() = '\''; - str.back() = '\''; - - stream.setText(ctx->start->getStartIndex(), str.c_str()); - } - else - { - throw PGErrorWrapperException(ERROR, - ERRCODE_INTERNAL_ERROR, - "double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF", 0, 0); - } - } - else - { - Assert(str.front() == '\''); - Assert(str.back() == '\''); - } - } - } - - void enterExecute_parameter(TSqlParser::Execute_parameterContext *ctx) override - { - // An execute_parameter represents a parameter in an EXECUTE statement. - // The grammar says that an execute_parameter may be a constant, an id(entifier), - // a LOCAL_ID (@name), or the word DEFAULT. We don't have to mutate a LOCAL_ID - // or DEFAULT - // - // If we find a double-quoted string constant, we change it to a single-quoted - // string constant. - // - // If we find a double-quoted identifier, we change it to a single-quoted - // string context. - // - // Examples: - // - // exec myproc test -> ctx->id (test) - // don't mutate, test is an identifier - // - // exec myproc 'test' -> ctx->constant ('test') - // don't mutate, 'test' is a string literal - // - // exec myproc "test" (QUOTED_IDENTIFIER=ON) -> ctx->id("test") - // mutate to a single-quoted string literal - // - // exec myproc "test" (QUOTED_IDENTIFIER=OFF) -> ctx->constant("test") - // mutate to a single-quoted string literal - - std::string argStr; - if (ctx->constant()) - argStr = getFullText(ctx->constant()); - else if (ctx->id()) - argStr = getFullText(ctx->id()); - - if (ctx->constant() || ctx->id()) - { - if (argStr.front() == '"' && argStr.back() == '"') - { - // if it's sp_tables, we will rewrite this into - // exec sp_tables "test" -> exec sp_tables 'test' - // exec sp_tables "'test'" -> exec sp_tables '''test''' - if (pg_strcasecmp(getProcNameFromExecParam(ctx).c_str() , "sp_tables") == 0) - { - double_quota_places.push_back(parameterIndex); - } - argStr.front() = '\''; - argStr.back() = '\''; - stream.setText(ctx->start->getStartIndex(), argStr.c_str()); - } - } - parameterIndex++; - } - void enterFunc_proc_name_schema(TSqlParser::Func_proc_name_schemaContext *ctx) override { // We are looking at a function name; it may be a function call, or a @@ -2004,7 +2471,7 @@ class tsqlMutator : public TSqlParserBaseListener // According to the grammar, an id can be any of the following: // - // id + // id // : ID // | DOUBLE_QUOTE_ID // | SQUARE_BRACKET_ID @@ -2142,6 +2609,95 @@ class tsqlMutator : public TSqlParserBaseListener } } } + } + + void enterProcedure_param(TSqlParser::Procedure_paramContext *ctx) override + { + if (ctx->expression()) { + in_procedure_parameter = true; + } + } + + void enterFull_column_name(TSqlParser::Full_column_nameContext *ctx) override + { + if (in_procedure_parameter) { + in_procedure_parameter_id = true; + } + } + + void exitProcedure_param(TSqlParser::Procedure_paramContext *ctx) override + { + in_procedure_parameter = false; + in_procedure_parameter_id = false; + } + + void exitId(TSqlParser::IdContext *ctx) override + { + if (in_procedure_parameter_id) + { + // This is a string parameter default which has been parsed as an identifier. + // Put quotes around it: even though it is an identifier in the ANTLR parse tree, it will then be + // parsed as a string by the backend parser + std::string str = getFullText(ctx); + + // When it's a bracketed identifier, remove the delimiters as T-SQL treats it as a string + // When it's a quoted identifier, T-SQL also treats it as a string independent of the QUOTED_IDENTIFIER setting + // (as we get here, it means QUOTED_IDENTIFIER=ON) + // When it none of the above, it is an unquoted string + if (str.front() == '[') { + Assert(str.back() == ']'); + + // Temporarily turn this into a double-quoted string so that we can handle embedded quotes. + // Since embedded double quotes inside a bracketed identifier are not escaped (as they would be in a + // double-quoted string), escape them first. We cannot just call rewriteDoubeQuotedString() since if we'd + // have two adjacent double quotes, i.e. [a""b], this would then become [a"b] so we'd lose one quote. + str = escapeDoubleQuotes(str); + str = '"' + str.substr(1,str.length()-2) + '"'; + str = rewriteDoubleQuotedString(str); + } + else if (str.front() == '"') { + Assert(str.back() == '"'); + str = rewriteDoubleQuotedString(str); + } + else { + // Unquoted string, add quotes: there cannot be any quotes in the string otherwise it would + // not have been parsed as an identifier + str = "'" + str + "'"; + } + + rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(getFullText(ctx), str))); + } + } + + void exitChar_string(TSqlParser::Char_stringContext *ctx) override + { + if (in_procedure_parameter) + { + std::string str = getFullText(ctx); + if (str.front() == 'N') + { + // This is only to make the assertion on str.front() easy (below) + str.erase(0, 1); + } + + if (str.front() == '\'') + { + // This is a single-quoted string used as parameter default: no further action needed + Assert(str.back() == '\''); + } + else + { + // This is a double-quoted string used as parameter default. + // (as we get here, it means QUOTED_IDENTIFIER=OFF) + + Assert(str.front() == '"'); + Assert(str.back() == '"'); + + // Change to PG-compatible single-quoted string + str = rewriteDoubleQuotedString(str); + rewritten_query_fragment.emplace(std::make_pair(ctx->start->getStartIndex(), std::make_pair(getFullText(ctx), str))); + } + } } }; @@ -2208,6 +2764,10 @@ static void process_query_specification( } } + bool is_freetext_predicate = false; + if(qctx->where) + is_freetext_predicate = check_freetext_predicate(qctx->where); + PLtsql_expr *expr = mutator->expr; ParserRuleContext* baseCtx = mutator->ctx; @@ -2215,7 +2775,7 @@ static void process_query_specification( if (qctx->table_sources()) { for (auto tctx : qctx->table_sources()->table_source_item()) // from-clause (to remove hints) - post_process_table_source(tctx, expr, baseCtx); + post_process_table_source(tctx, expr, baseCtx, is_freetext_predicate); } /* handle special alias syntax and quote alias */ @@ -2382,12 +2942,12 @@ antlr_parse_query(const char *sourceText, bool useSLLParsing) { tree::ParseTree *tree = nullptr; /* - * The sematnic of "RETURN SELECT ..." depends on whether it is used in Inlined Table Value Function or not. + * The semantic of "RETURN SELECT ..." depends on whether it is used in Inlined Table Value Function or not. * In ITVF, they should be interpeted as return a result tuple of SELECT statement. * but in the other case (i.e. procedure or SQL batch), it should be interpreted as two separate statements like "RETURN; SELECT ..." * * Currently, we have only proc_body in input so accessing pltsql_curr_compile to check this is a body of ITVF or not. - * If if it is ITVF, we parsed it with func_body_return_select_body grammar. + * If it is ITVF, we parsed it with func_body_return_select_body grammar. */ if (pltsql_curr_compile && pltsql_curr_compile->is_itvf) /* special path to itvf */ tree = parser.func_body_return_select_body(); @@ -2693,13 +3253,13 @@ rewriteBatchLevelStatement( /* DML trigger can have two WITH. one for trigger options and the other for WITH APPEND */ if (cctx->WITH().size() > 1 || (cctx->WITH().size() == 1 && !cctx->APPEND())) { - size_t num_commas_in_dml_trigger_operaion = cctx->COMMA().size(); + size_t num_commas_in_dml_trigger_operation = cctx->COMMA().size(); auto options = cctx->trigger_option(); /* COMMA is shared between dml_trigger_operation and WITH-clause. calculate the number of COMMA so that it can be removed properly */ - num_commas_in_dml_trigger_operaion -= (cctx->trigger_option().size() - 1); + num_commas_in_dml_trigger_operation -= (cctx->trigger_option().size() - 1); auto commas = cctx->COMMA(); std::vector commas_in_with_clause; - commas_in_with_clause.insert(commas_in_with_clause.begin(), commas.begin() , commas.end() - num_commas_in_dml_trigger_operaion); + commas_in_with_clause.insert(commas_in_with_clause.begin(), commas.begin() , commas.end() - num_commas_in_dml_trigger_operation); GetTokenFunc getToken = [](TSqlParser::Trigger_optionContext* o) { if (o->execute_as_clause()) return o->execute_as_clause()->CALLER(); @@ -3299,7 +3859,7 @@ makeTsqlExpr(const std::string &fragment, bool addSelect) PLtsql_expr *result = (PLtsql_expr *) palloc0(sizeof(*result)); if (addSelect) - result->query = pstrdup((std::string("SELECT ") + fragment).c_str()); + result->query = pstrdup((fragment_SELECT_prefix + fragment).c_str()); else result->query = pstrdup(fragment.c_str()); @@ -3307,7 +3867,7 @@ makeTsqlExpr(const std::string &fragment, bool addSelect) result->paramnos = NULL; result->rwparam = -1; result->ns = pltsql_ns_top(); - + return result; } @@ -3425,6 +3985,22 @@ void extractTableHints(TSqlParser::With_table_hintsContext *tctx, std::string ta } } +std::string extractSchemaName(TSqlParser::Ddl_objectContext *dctx, TSqlParser::Table_source_itemContext *tctx) +{ + std::string schema_name = ""; + if (dctx == nullptr) + { + if (tctx->full_object_name() && tctx->full_object_name()->schema) + schema_name = stripQuoteFromId(tctx->full_object_name()->schema); + } + else + { + if (dctx->full_object_name() && dctx->full_object_name()->schema) + schema_name = stripQuoteFromId(dctx->full_object_name()->schema); + } + return schema_name; +} + std::string extractTableName(TSqlParser::Ddl_objectContext *dctx, TSqlParser::Table_source_itemContext *tctx) { std::string table_name; @@ -3717,10 +4293,13 @@ makeIfStmt(TSqlParser::If_statementContext *ctx) result->cmd_type = PLTSQL_STMT_IF; result->lineno = getLineNo(ctx); - result->cond = makeTsqlExpr(ctx->search_condition(), true); - // Note that we record the then_body and the else_body - // in exitIf_statement() + /* + * Note that + * 1/ We fill in result->cond during exitIf_statement so that search_condition would have + * been rewritten at that point. + * 2/ We record the then_body and the else_body in exitIf_statement(). + */ return result; } @@ -3741,8 +4320,11 @@ makeReturnStmt(TSqlParser::Return_statementContext *ctx) std::string expr = std::string("CAST( ") + ::getFullText(ctx->expression()) + " AS INT)"; result->expr = makeTsqlExpr(expr, true); } - else + else + { result->expr = makeTsqlExpr(ctx->expression(), true); + recordSelectFragmentOffsets(ctx->parent, ctx->expression()); + } } else result->expr = NULL; @@ -3858,10 +4440,10 @@ void * makeWhileStmt(TSqlParser::While_statementContext *ctx) { PLtsql_stmt_while *result = (PLtsql_stmt_while *) palloc0(sizeof(*result)); - result->cmd_type = PLTSQL_STMT_WHILE; - result->cond = makeTsqlExpr(ctx->search_condition(), true); - + + /* We will populate result->cond during exitSearch_condition() */ + return result; } @@ -3872,6 +4454,7 @@ makePrintStmt(TSqlParser::Print_statementContext *ctx) result->cmd_type = PLTSQL_STMT_PRINT; result->exprs = list_make1(makeTsqlExpr(ctx->expression(), true)); + recordSelectFragmentOffsets(ctx->parent, ctx->expression()); return result; } @@ -3891,9 +4474,11 @@ makeRaiseErrorStmt(TSqlParser::Raiseerror_statementContext *ctx) // msg, severity, state result->params = lappend(result->params, makeTsqlExpr(ctx->msg->getText(), true)); + recordSelectFragmentOffsets(ctx->parent, ctx->raiseerror_msg()); + result->params = lappend(result->params, makeTsqlExpr(ctx->severity, true)); result->params = lappend(result->params, makeTsqlExpr(ctx->state, true)); - + // additional arguments if (ctx->argument.size() > 20) throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, "Too many substitution parameters for RAISERROR. Cannot exceed 20 substitution parameters.", getLineAndPos(ctx)); @@ -3934,13 +4519,13 @@ makeRaiseErrorStmt(TSqlParser::Raiseerror_statementContext *ctx) } PLtsql_stmt * -makeInitializer(PLtsql_variable *var, TSqlParser::ExpressionContext *val) +makeInitializer(int varno, int lineno, TSqlParser::ExpressionContext *val) { PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) palloc0(sizeof(*result)); result->cmd_type = PLTSQL_STMT_ASSIGN; - result->lineno = 0; - result->varno = var->dno; + result->lineno = lineno; + result->varno = varno; result->expr = makeTsqlExpr(val, true); // We've created an assignment statement out of the @@ -3951,14 +4536,11 @@ makeInitializer(PLtsql_variable *var, TSqlParser::ExpressionContext *val) // the nearest enclosing block - variables are scoped // to the function/procedure/batch. - //rootInitializers = lappend(rootInitializers, result); - return (PLtsql_stmt *) result; } - std::vector -makeDeclareStmt(TSqlParser::Declare_statementContext *ctx) +makeDeclareStmt(TSqlParser::Declare_statementContext *ctx, std::map *declare_local_expr) { std::vector result; @@ -3967,7 +4549,7 @@ makeDeclareStmt(TSqlParser::Declare_statementContext *ctx) // declared variables as a vector. // // Please note that we should keep the order of - // statement becaue initializer can be a function or + // statement because initializer can be a function or // global variable so they can be affected by // preceeding statements. That's the reason why // we don't use rootInitializer any more. @@ -4024,8 +4606,21 @@ makeDeclareStmt(TSqlParser::Declare_statementContext *ctx) if (var->dtype == PLTSQL_DTYPE_TBL) result.push_back(makeDeclTableStmt(var, type, getLineNo(ctx))); - else if (local->expression()) - result.push_back(makeInitializer(var, local->expression())); + else if (local->expression()) + { + PLtsql_stmt *e = makeInitializer(var->dno, getLineNo(ctx), local->expression()); + result.push_back(e); + + // DECLARE is different from other stmts under Another_statement, in that multiple fragments may be created. + // By associating these with the expression() node, they can be stored without issues (otherwise, exitAnother_statement + // would use the context of the Another_statement rule for all fragments and all but the last would be lost). + (*declare_local_expr).emplace(std::make_pair(e, local->expression())); + + // Each variable assignment in DECLARE becomes a fragment, for which rewriting may be required. Since all rewrite actions + // will be accumulated by the time the rewriting happens (in exitAnother_statement), we need to keep track of where + // the assignment is located (start-end of range) so that we can apply the rewrites correctly. + recordSelectFragmentOffsets(local->expression(), local->expression()); + } } } } @@ -4126,6 +4721,26 @@ static bool is_valid_set_option(std::string val) (pg_strcasecmp("QUERY_GOVERNOR_COST_LIMIT", val.c_str()) == 0); } +static PLtsql_var * build_babelfish_guc_variable(TSqlParser::Special_variableContext *guc_ctx) +{ + PLtsql_var *var; + int type; + std::string command = ::getFullText(guc_ctx); + std::transform(command.begin(), command.end(), command.begin(), ::tolower); + + if (guc_ctx->ROWCOUNT() || guc_ctx->DATEFIRST()) + type = INT4OID; + else + type = TEXTOID; + + var = (PLtsql_var *) pltsql_build_variable(command.c_str(), + 0, + pltsql_build_datatype(type, -1, InvalidOid, NULL), + false); + var->is_babelfish_guc = true; + return var; +} + PLtsql_stmt * makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) { @@ -4135,8 +4750,6 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) if (expr && localID) { - PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) palloc0(sizeof(*result)); - auto targetText = ::getFullText(localID); int dno = check_assignable(localID); @@ -4146,10 +4759,11 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) char *target = pstrdup(targetText.c_str()); pltsql_parse_word(target, target, &wdatum, &word); - result->cmd_type = PLTSQL_STMT_ASSIGN; - result->lineno = getLineNo(ctx); - result->varno = dno; - result->expr = makeTsqlExpr(expr, true); + PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) makeInitializer(dno, getLineNo(ctx), expr); + + int posStart = expr->getStart()->getStartIndex(); + int posEnd = expr->getStop()->getStopIndex() ; + int posBracket = 0; // assigned below if (ctx->assignment_operator()) { @@ -4182,12 +4796,27 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) * to * SET @var = "@var" ^ (5 -1) */ + StringInfoData new_query; - initStringInfo(&new_query); - appendStringInfo(&new_query, "SELECT \"%s\" %s (%s)", target, rewrite_assign_operator(anode), result->expr->query + sizeof("SELECT")); + initStringInfo(&new_query); + appendStringInfo(&new_query, "SELECT \"%s\" %s (%s)", + target, + rewrite_assign_operator(anode), + result->expr->query + strlen("SELECT ")); // Pointer arithmetic: skip over the string + // preceding the expression, prior to the rewrite result->expr->query = new_query.data; + + // Record how many chars are added prior to the expression + // "SELECT " : preceding chars before this reformatting the expression + // +1 : the opening bracket + posBracket = strcspn(new_query.data, "(") - strlen("SELECT ") + 1; + } + // Each variable assignment becomes a fragment, for which rewriting may be required. We need to keep track of where + // the assignment is located (start-end of range) so that we can apply the rewrites correctly + recordSelectFragmentOffsets(ctx, posStart, posEnd, posBracket); + return (PLtsql_stmt *) result; } else if (ctx->CURSOR()) @@ -4311,7 +4940,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; @@ -4326,6 +4981,27 @@ makeSetStatement(TSqlParser::Set_statementContext *ctx, tsqlBuilder &builder) } else if (set_special_ctx->BABELFISH_STATISTICS() && set_special_ctx->PROFILE()) return makeSetExplainModeStatement(ctx, false); + else if(set_special_ctx->ISOLATION()) + { + PLtsql_stmt_execsql *stmt = (PLtsql_stmt_execsql *) makeSQL(ctx); + stmt->is_set_tran_isolation = true; + return (PLtsql_stmt *) stmt; + } + else if(set_special_ctx->special_variable()) + { + TSqlParser::Special_variableContext *guc_ctx = static_cast (set_special_ctx->special_variable()); + /* build expression with the input variable */ + PLtsql_expr* input_expr = makeTsqlExpr(getFullText(set_special_ctx->LOCAL_ID()), true); + /* build target variable for this GUC, so that in backend we can identify that target is GUC */ + PLtsql_var *target_var = build_babelfish_guc_variable(guc_ctx); + /* assign expression to target */ + PLtsql_stmt_assign *result = (PLtsql_stmt_assign *) palloc0(sizeof(*result)); + result->cmd_type = PLTSQL_STMT_ASSIGN; + result->lineno = getLineNo(ctx); + result->varno = target_var->dno; + result->expr = input_expr; + return (PLtsql_stmt *) result; + } else return makeSQL(ctx); } @@ -4475,7 +5151,6 @@ makeInsertBulkStatement(TSqlParser::Dml_statementContext *ctx) } } } - attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); return (PLtsql_stmt *) stmt; } @@ -4503,109 +5178,14 @@ makeExecuteStatement(TSqlParser::Execute_statementContext *ctx) } } std::string expr_query = ss.str(); - result->expr = makeTsqlExpr(expr_query, true); - - return (PLtsql_stmt *) result; - } - else /* execute a stored procedure or function */ - { - std::string func_proc_name; - TSqlParser::Execute_statement_argContext *func_proc_args = body->execute_statement_arg(); - bool is_cross_db = false; - std::string proc_name; - std::string schema_name; - std::string db_name; - - if (body->func_proc_name_server_database_schema()) - { - func_proc_name = ::getFullText(body->func_proc_name_server_database_schema()); - if (body->func_proc_name_server_database_schema()->database) - { - db_name = stripQuoteFromId(body->func_proc_name_server_database_schema()->database); - if (!string_matches(db_name.c_str(), get_cur_db_name())) - is_cross_db = true; - } - if (body->func_proc_name_server_database_schema()->schema) - schema_name = stripQuoteFromId(body->func_proc_name_server_database_schema()->schema); - if (body->func_proc_name_server_database_schema()->procedure) - proc_name = stripQuoteFromId(body->func_proc_name_server_database_schema()->procedure); - } - else - { - /* LOCAL_ID can be placed on return_status and/or proc_var. choose the corresponding index, depending on whether return_status if exists or not. */ - Assert(body->proc_var); - func_proc_name = ::getFullText(body->return_status ? body->LOCAL_ID()[1] : body->LOCAL_ID()[0]); - } - Assert(!func_proc_name.empty()); - - int lineno = getLineNo(ctx); - int return_code_dno = -1; - - auto *localID = body->return_status ? body->LOCAL_ID()[0] : nullptr; - if (localID) - return_code_dno = getVarno(localID); - - if (is_sp_proc(func_proc_name)) - return makeSpStatement(func_proc_name, func_proc_args, lineno, return_code_dno); - - PLtsql_stmt_exec *result = (PLtsql_stmt_exec *) palloc0(sizeof(*result)); - result->cmd_type = PLTSQL_STMT_EXEC; - result->lineno = lineno; - result->is_call = true; - result->return_code_dno = return_code_dno; - result->paramno = 0; - result->params = NIL; - // record whether stmt is cross-db - if (is_cross_db) - result->is_cross_db = true; - - if (!proc_name.empty()) - { - result->proc_name = pstrdup(downcase_truncate_identifier(proc_name.c_str(), proc_name.length(), true)); - } - if (!schema_name.empty()) - { - result->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); - } - if (!db_name.empty()) - { - result->db_name = pstrdup(downcase_truncate_identifier(db_name.c_str(), db_name.length(), true)); - } - - if (func_proc_args) - { - std::vector params; - makeSpParams(func_proc_args, params); - - for (size_t i = 0; i < params.size(); i++) - { - result->params = lappend(result->params, params[i]); - result->paramno++; - } - } - - std::string rewritten_name = ""; - if (body->func_proc_name_server_database_schema()) - { - // rewrite func/proc name if database/schema is omitted (i.e. EXEC ..proc1) - GetCtxFunc getDatabase = [](TSqlParser::Func_proc_name_server_database_schemaContext *o) { return o->database; }; - GetCtxFunc getSchema = [](TSqlParser::Func_proc_name_server_database_schemaContext *o) { return o->schema; }; - rewritten_name = rewrite_object_name_with_omitted_db_and_schema_name(body->func_proc_name_server_database_schema(), getDatabase, getSchema); - } - - std::stringstream ss; - std::string name = (!rewritten_name.empty() ? rewritten_name : func_proc_name); - // Rewrite proc name to sp_* if the schema is "dbo" and proc name starts with "sp_" - if (pg_strncasecmp(name.c_str(), "dbo.sp_", 6) == 0) - name.erase(name.begin() + 0, name.begin() + 4); - ss << "EXEC " << name; - if (func_proc_args) - ss << " " << ::getFullText(func_proc_args); - std::string expr_query = ss.str(); - result->expr = makeTsqlExpr(expr_query, false); - + result->expr = makeTsqlExpr(expr_query, true); + return (PLtsql_stmt *) result; } + else /* execute a stored procedure or function */ + { + return makeExecuteProcedure(ctx, "execute_statement"); + } } PLtsql_stmt * @@ -4698,7 +5278,7 @@ makeOpenCursorStatement(TSqlParser::Cursor_statementContext *ctx) } PLtsql_stmt * -makeFetchCurosrStatement(TSqlParser::Fetch_cursorContext *ctx) +makeFetchCursorStatement(TSqlParser::Fetch_cursorContext *ctx) { PLtsql_stmt_fetch *result = (PLtsql_stmt_fetch *) palloc(sizeof(PLtsql_stmt_fetch)); result->cmd_type = PLTSQL_STMT_FETCH; @@ -4829,7 +5409,7 @@ makeCursorStatement(TSqlParser::Cursor_statementContext *ctx) else if (ctx->OPEN()) return makeOpenCursorStatement(ctx); else if (ctx->fetch_cursor()) - return makeFetchCurosrStatement(ctx->fetch_cursor()); + return makeFetchCursorStatement(ctx->fetch_cursor()); else if (ctx->CLOSE()) return makeCloseCursorStatement(ctx); else if (ctx->DEALLOCATE()) @@ -4859,6 +5439,27 @@ makeUseStatement(TSqlParser::Use_statementContext *ctx) return (PLtsql_stmt *) result; } +PLtsql_stmt * +makeKillStatement(TSqlParser::Kill_statementContext *ctx) +{ + PLtsql_stmt_kill *result = (PLtsql_stmt_kill *) palloc0(sizeof(*result)); + + result->cmd_type = PLTSQL_STMT_KILL; + result->lineno = getLineNo(ctx); + + /* + * Only supporting numeric argument for the spid, + * other flavours of KILL are intercepted in the parser. + */ + if (ctx->kill_process()) { + char *strtol_endptr; + std::string spidStr = ::getFullText(ctx->kill_process()); + result->spid = (int) strtol(spidStr.c_str(), &strtol_endptr, 10); + } + + return (PLtsql_stmt *) result; +} + PLtsql_stmt * makeGrantdbStatement(TSqlParser::Security_statementContext *ctx) { @@ -4917,6 +5518,108 @@ makeGrantdbStatement(TSqlParser::Security_statementContext *ctx) } } } + if (ctx->grant_statement() && ctx->grant_statement()->ON() && ctx->grant_statement()->permission_object() + && ctx->grant_statement()->permission_object()->object_type() && ctx->grant_statement()->permission_object()->object_type()->SCHEMA()) + { + if (ctx->grant_statement()->TO() && ctx->grant_statement()->principals() && ctx->grant_statement()->permissions()) + { + PLtsql_stmt_grantschema *result = (PLtsql_stmt_grantschema *) palloc0(sizeof(PLtsql_stmt_grantschema)); + result->cmd_type = PLTSQL_STMT_GRANTSCHEMA; + result->lineno = getLineNo(ctx->grant_statement()); + result->is_grant = true; + std::string schema_name; + if (ctx->grant_statement()->permission_object()->full_object_name()->object_name) + { + schema_name = stripQuoteFromId(ctx->grant_statement()->permission_object()->full_object_name()->object_name); + result->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + } + List *grantee_list = NIL; + for (auto prin : ctx->grant_statement()->principals()->principal_id()) + { + if (prin->id()) + { + std::string id_str = ::getFullText(prin->id()); + char *grantee_name = pstrdup(downcase_truncate_identifier(id_str.c_str(), id_str.length(), true)); + grantee_list = lappend(grantee_list, grantee_name); + } + } + List *privilege_list = NIL; + for (auto perm: ctx->grant_statement()->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->EXEC()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->SELECT()) + privilege_list = lappend(privilege_list, (void *)"select"); + if (single_perm->INSERT()) + privilege_list = lappend(privilege_list, (void *)"insert"); + if (single_perm->UPDATE()) + privilege_list = lappend(privilege_list, (void *)"update"); + if (single_perm->DELETE()) + privilege_list = lappend(privilege_list, (void *)"delete"); + if (single_perm->REFERENCES()) + privilege_list = lappend(privilege_list, (void *)"references"); + } + result->privileges = privilege_list; + if (ctx->grant_statement()->WITH()) + result->with_grant_option = true; + result->grantees = grantee_list; + return (PLtsql_stmt *) result; + } + } + + if (ctx->revoke_statement() && ctx->revoke_statement()->ON() && ctx->revoke_statement()->permission_object() + && ctx->revoke_statement()->permission_object()->object_type() && ctx->revoke_statement()->permission_object()->object_type()->SCHEMA()) + { + if (ctx->revoke_statement()->FROM() && ctx->revoke_statement()->principals() && ctx->revoke_statement()->permissions()) + { + PLtsql_stmt_grantschema *result = (PLtsql_stmt_grantschema *) palloc0(sizeof(PLtsql_stmt_grantschema)); + result->cmd_type = PLTSQL_STMT_GRANTSCHEMA; + result->lineno = getLineNo(ctx->revoke_statement()); + result->is_grant = false; + std::string schema_name; + if (ctx->revoke_statement()->permission_object()->full_object_name()->object_name) + { + schema_name = stripQuoteFromId(ctx->revoke_statement()->permission_object()->full_object_name()->object_name); + result->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + } + List *grantee_list = NIL; + for (auto prin : ctx->revoke_statement()->principals()->principal_id()) + { + if (prin->id()) + { + std::string id_str = ::getFullText(prin->id()); + char *grantee_name = pstrdup(downcase_truncate_identifier(id_str.c_str(), id_str.length(), true)); + grantee_list = lappend(grantee_list, grantee_name); + } + } + List *privilege_list = NIL; + for (auto perm: ctx->revoke_statement()->permissions()->permission()) + { + auto single_perm = perm->single_permission(); + if (single_perm->EXECUTE()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->EXEC()) + privilege_list = lappend(privilege_list, (void *)"execute"); + if (single_perm->SELECT()) + privilege_list = lappend(privilege_list, (void *)"select"); + if (single_perm->INSERT()) + privilege_list = lappend(privilege_list, (void *)"insert"); + if (single_perm->UPDATE()) + privilege_list = lappend(privilege_list, (void *)"update"); + if (single_perm->DELETE()) + privilege_list = lappend(privilege_list, (void *)"delete"); + if (single_perm->REFERENCES()) + privilege_list = lappend(privilege_list, (void *)"references"); + } + result->privileges = privilege_list; + result->grantees = grantee_list; + return (PLtsql_stmt *) result; + } + } + PLtsql_stmt *result; result = makeExecSql(ctx); attachPLtsql_fragment(ctx, result); @@ -4951,10 +5654,11 @@ std::vector makeAnother(TSqlParser::Another_statementContext *ctx, tsqlBuilder &builder) { std::vector result; + std::map declare_local_expr; if (ctx->declare_statement()) { - std::vector decl_result = makeDeclareStmt(ctx->declare_statement()); + std::vector decl_result = makeDeclareStmt(ctx->declare_statement(), &declare_local_expr); result.insert(result.end(), decl_result.begin(), decl_result.end()); } else if (ctx->set_statement()) @@ -4971,42 +5675,172 @@ makeAnother(TSqlParser::Another_statementContext *ctx, tsqlBuilder &builder) result.push_back(makeTransactionStatement(ctx->transaction_statement())); /* relaying transaction statement to main parser */ else if (ctx->use_statement()) result.push_back(makeUseStatement(ctx->use_statement())); + else if (ctx->kill_statement()) + result.push_back(makeKillStatement(ctx->kill_statement())); // FIXME: handle remaining statement types - for (PLtsql_stmt *stmt : result) - attachPLtsql_fragment(ctx, stmt); + for (PLtsql_stmt *stmt : result) + { + // Associate each fragement with a tree node + if (declare_local_expr.find(stmt) != declare_local_expr.end()) + { + attachPLtsql_fragment(declare_local_expr.at(stmt), stmt); + } + else if (ctx->set_statement()) + { + attachPLtsql_fragment(ctx->set_statement(), stmt); + } + else + { + attachPLtsql_fragment(ctx, stmt); + } + } return result; } - + +// For stored procedure calls without EXECUTE keyword, with the procedure name as first thing in the batch: PLtsql_stmt * makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx) { + return makeExecuteProcedure(ctx, "execute_body_batch"); +} + +// For stored procedure calls, or functions called with EXECUTE: +PLtsql_stmt * +makeExecuteProcedure(ParserRuleContext *ctx, std::string call_type) +{ + Assert(string_matches(call_type.c_str(), "execute_statement") || string_matches(call_type.c_str(), "execute_body_batch")); + Assert(ctx); + + TSqlParser::Func_proc_name_server_database_schemaContext *ctx_name = nullptr; + TSqlParser::Execute_statement_argContext *func_proc_args = nullptr; + TSqlParser::Execute_bodyContext *body = nullptr; + std::string schema_name; std::string proc_name; - bool is_cross_db = false; std::string db_name; - std::string func_proc_name = ::getFullText(ctx->func_proc_name_server_database_schema()); - if (ctx->func_proc_name_server_database_schema()->database) + std::string name; + bool is_cross_db = false; + int lineno = getLineNo(ctx); + int return_code_dno = -1; + std::string execKeywd = "EXEC"; // DO NOT CHANGE! + + // Use a boolean vor convenience + bool execute_statement = string_matches(call_type.c_str(), "execute_statement") ? true : false; + + size_t startPos = ctx->start->getStartIndex(); // start position of statement + size_t namePos = -1; // start position of procedure name + size_t argPos = -1; // start position of first argument + + // Set up calltype-dependent values + if (execute_statement) { - db_name = stripQuoteFromId(ctx->func_proc_name_server_database_schema()->database); - if (!string_matches(db_name.c_str(), get_cur_db_name())) - is_cross_db = true; + TSqlParser::Execute_statementContext *ctxES = (TSqlParser::Execute_statementContext *) ctx; + + if (ctxES->EXECUTE()) execKeywd = "EXEC "; // same length as EXECUTE. DO NOT CHANGE! + body = ctxES->execute_body(); + Assert(body); + + ctx_name = body->func_proc_name_server_database_schema(); + func_proc_args = body->execute_statement_arg(); } - if (ctx->func_proc_name_server_database_schema()->schema) - schema_name = stripQuoteFromId(ctx->func_proc_name_server_database_schema()->schema); - if (ctx->func_proc_name_server_database_schema()->procedure) - proc_name = stripQuoteFromId(ctx->func_proc_name_server_database_schema()->procedure); - Assert(!func_proc_name.empty()); - TSqlParser::Execute_statement_argContext *func_proc_args = ctx->execute_statement_arg(); - - int lineno = getLineNo(ctx); - int return_code_dno = -1; + else // execute_body_batch + { + TSqlParser::Execute_body_batchContext *ctxEBB = (TSqlParser::Execute_body_batchContext *) ctx; + ctx_name = ctxEBB->func_proc_name_server_database_schema(); + func_proc_args = ctxEBB->execute_statement_arg(); + Assert(ctx_name); + } + - if (is_sp_proc(func_proc_name)) - return makeSpStatement(func_proc_name, func_proc_args, lineno, return_code_dno); + if (ctx_name) + { + // Get the name of procedure being executed, and split up in parts + name = ::getFullText(ctx_name); + Assert(!name.empty()); + + // Original position of the name + namePos = ctx_name->start->getStartIndex(); + + if (ctx_name->database) + { + db_name = stripQuoteFromId(ctx_name->database); + if (!string_matches(db_name.c_str(), get_cur_db_name())) + { + is_cross_db = true; + } + } + + if (ctx_name->schema) + { + schema_name = stripQuoteFromId(ctx_name->schema); + } + + if (ctx_name->procedure) + { + proc_name = stripQuoteFromId(ctx_name->procedure); + } + + // Note: previous code performed rewriting here for procedure names with leading dots (EXEC ..proc1) + // This is now performed in exitFunc_proc_name_server_database_schema() which is called via the mutator (previously, it wasn't). + + // For sp_* procs, truncate proc name to sp_* if the schema is "dbo" or "sys" or has leading dots + // ToDo: handle 'EXEC mydb..sp_proc' where sp_proc gets executed in the context of 'mydb', even when the current DB is not 'mydb' + if ((pg_strncasecmp(name.c_str(), "..dbo.sp_", 9) == 0) || (pg_strncasecmp(name.c_str(), "..sys.sp_", 9) == 0)) + { + name.erase(name.begin() + 0, name.begin() + 6); + } + else if ((pg_strncasecmp(name.c_str(), ".dbo.sp_", 8) == 0) || (pg_strncasecmp(name.c_str(), ".sys.sp_", 8) == 0)) + { + name.erase(name.begin() + 0, name.begin() + 5); + } + else if ((pg_strncasecmp(name.c_str(), "dbo.sp_", 7) == 0) || (pg_strncasecmp(name.c_str(), "sys.sp_", 7) == 0)) + { + name.erase(name.begin() + 0, name.begin() + 4); + } + else if (pg_strncasecmp(name.c_str(), ".sp_", 4) == 0) + { + name.erase(name.begin() + 0, name.begin() + 1); + } + else if (pg_strncasecmp(name.c_str(), "..sp_", 5) == 0) + { + name.erase(name.begin() + 0, name.begin() + 2); + } + else if (pg_strncasecmp(name.c_str(), "...sp_", 6) == 0) + { + name.erase(name.begin() + 0, name.begin() + 3); + } + } + + if (!ctx_name && execute_statement) + { + // LOCAL_ID can be placed on return_status and/or proc_var. choose the corresponding index, depending on whether return_status exists or not + Assert(body->proc_var); + name = ::getFullText(body->return_status ? body->LOCAL_ID()[1] : body->LOCAL_ID()[0]); + Assert(!name.empty()); + + namePos = body->proc_var->getStartIndex(); + } + if (execute_statement) + { + // Check for return status variable: EXEC @var = proc + auto *localID = body->return_status ? body->LOCAL_ID()[0] : nullptr; + if (localID) + { + return_code_dno = getVarno(localID); + } + } + + if (is_sp_proc(name)) + { + // If this is one of the special stored procs, exit here + return makeSpStatement(name, func_proc_args, lineno, return_code_dno); + } + + // Build the statement PLtsql_stmt_exec *result = (PLtsql_stmt_exec *) palloc0(sizeof(*result)); result->cmd_type = PLTSQL_STMT_EXEC; result->lineno = lineno; @@ -5014,22 +5848,28 @@ makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx) result->return_code_dno = return_code_dno; result->paramno = 0; result->params = NIL; - // record whether stmt is cross-db - if (is_cross_db) - result->is_cross_db = true; + result->is_cross_db = is_cross_db; // Record whether this is a cross-db call + // Handle name parts if (!proc_name.empty()) + { result->proc_name = pstrdup(downcase_truncate_identifier(proc_name.c_str(), proc_name.length(), true)); + } if (!schema_name.empty()) + { result->schema_name = pstrdup(downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); + } if (!db_name.empty()) + { result->db_name = pstrdup(downcase_truncate_identifier(db_name.c_str(), db_name.length(), true)); + } + // Handle arguments if (func_proc_args) { + argPos = func_proc_args->start->getStartIndex(); std::vector params; makeSpParams(func_proc_args, params); - for (size_t i = 0; i < params.size(); i++) { result->params = lappend(result->params, params[i]); @@ -5037,19 +5877,162 @@ makeExecBodyBatch(TSqlParser::Execute_body_batchContext *ctx) } } - std::stringstream ss; - // Rewrite proc name to sp_* if the schema is "dbo" and proc name starts with "sp_" - if (pg_strncasecmp(func_proc_name.c_str(), "dbo.sp_", 6) == 0) - func_proc_name.erase(func_proc_name.begin() + 0, func_proc_name.begin() + 4); - ss << "EXEC " << func_proc_name; - if (func_proc_args) - ss << " " << ::getFullText(func_proc_args); + // For execute_body_batch, there was no EXEC[UTE] keyword, so 'EXEC ' will be prepended; + // must account for the resulting offset + if (!execute_statement) + { + namePos += fragment_EXEC_prefix.length(); + argPos += fragment_EXEC_prefix.length(); + } + + // If there is a comment preceding the statement, startPos will be > 0 + namePos -= startPos; + Assert(namePos >= 0); + + // Build the statement text + std::stringstream ss; + if (execute_statement) + { + // In order for rewriting of the arguments to work correctly, they should be at the same position as in the original + // SQL text. + ss << execKeywd; + } + else + { + // For proc execution without EXECUTE, prepend 'EXEC ' + ss << fragment_EXEC_prefix; + } + int ssPos = ss.str().length(); + + // Because whitespace and comments will be ignored by the logic below, spaces are added as needed + // to keep the tokens at the same offsets as originally; this is required for rewriting + int spacesNeeded = (namePos - ssPos); + + ss << std::string(spacesNeeded, ' '); + ssPos += spacesNeeded; + + ss << name; + ssPos += name.length(); + + if (func_proc_args) + { + argPos -= startPos; + spacesNeeded = (argPos - ssPos); + Assert(spacesNeeded >= 0); + + ss << std::string(spacesNeeded, ' '); + ssPos += spacesNeeded; + + ss << ::getFullText(func_proc_args); + } std::string expr_query = ss.str(); result->expr = makeTsqlExpr(expr_query, false); return (PLtsql_stmt *) result; } +PLtsql_stmt* +makeDbccCheckidentStatement(TSqlParser::Dbcc_statementContext *ctx) +{ + PLtsql_stmt_dbcc *stmt = (PLtsql_stmt_dbcc *) palloc0(sizeof(*stmt)); + + std::string new_reseed_value; + std::string input_str; + int i; + char *db_name = NULL; + char *schema_name = NULL; + char *table_name = NULL; + char *input_str_to_split; + char **splited_object_name; + bool is_reseed = true; + bool no_infomsgs = false; + + stmt->cmd_type = PLTSQL_STMT_DBCC; + stmt->dbcc_stmt_type = PLTSQL_DBCC_CHECKIDENT; + + if (ctx->table_name_string()) + { + if(ctx->table_name_string()->table) + { + input_str = stripQuoteFromId(ctx->table_name_string()->table); + } + if (ctx->table_name_string()->char_string()) + { + input_str = ctx->table_name_string()->char_string()->STRING()->getSymbol()->getText(); + if (input_str.length() <= 2) + throw PGErrorWrapperException(ERROR, ERRCODE_INVALID_PARAMETER_VALUE, + "Parameter 1 is incorrect for this DBCC statement", + getLineAndPos(ctx->table_name_string())); + input_str = input_str.substr(1, input_str.length()-2); + } + if (ctx->RESEED()) + { + if (ctx->new_value) + { + if(ctx->MINUS()) + stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText().insert(0,"-")).c_str()); + else + stmt->dbcc_stmt_data.dbcc_checkident.new_reseed_value = pstrdup((ctx->new_value->getText()).c_str()); + } + } + else if (ctx->NORESEED()) + { + is_reseed = false; + } + + if(ctx->dbcc_options()) + { + if (pg_strcasecmp(::getFullText(ctx->dbcc_options()).c_str(), "NO_INFOMSGS") == 0) + { + no_infomsgs = true; + } + else + { + throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, + format_errmsg("\'%s\' is not a recognized option", + ::getFullText(ctx->dbcc_options()).c_str()), + getLineAndPos(ctx->dbcc_options())); + } + } + } + + input_str_to_split = pstrdup(input_str.c_str()); + + /* strip trailing whitespace from input string */ + i = strlen(input_str_to_split); + while (i > 0 && isspace((unsigned char) input_str_to_split[i - 1])) + input_str_to_split[--i] = '\0'; + + splited_object_name = split_object_name(input_str_to_split); + db_name = !strcmp(splited_object_name[1], "")? NULL : splited_object_name[1]; + schema_name = !strcmp(splited_object_name[2], "")? NULL : splited_object_name[2]; + table_name = !strcmp(splited_object_name[3], "")? NULL : splited_object_name[3]; + + if(db_name) + { + stmt->dbcc_stmt_data.dbcc_checkident.db_name = pstrdup(downcase_truncate_identifier(db_name, strlen(db_name), true)); + pfree(db_name); + } + if(schema_name) + { + stmt->dbcc_stmt_data.dbcc_checkident.schema_name = pstrdup(downcase_truncate_identifier(schema_name, strlen(schema_name), true)); + pfree(schema_name); + } + if(table_name) + { + stmt->dbcc_stmt_data.dbcc_checkident.table_name = pstrdup(downcase_truncate_identifier(table_name, strlen(table_name), true)); + pfree(table_name); + } + stmt->dbcc_stmt_data.dbcc_checkident.is_reseed = is_reseed; + stmt->dbcc_stmt_data.dbcc_checkident.no_infomsgs = no_infomsgs; + + pfree(splited_object_name); + pfree(input_str_to_split); + + attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); + return (PLtsql_stmt *) stmt; +} + // helper function to create target row PLtsql_row * create_select_target_row(const char *refname, size_t nfields, int lineno) @@ -5280,10 +6263,27 @@ void process_execsql_destination(TSqlParser::Dml_statementContext *ctx, PLtsql_s } } -static void post_process_table_source(TSqlParser::Table_source_itemContext *ctx, PLtsql_expr *expr, ParserRuleContext *baseCtx) +static bool check_freetext_predicate(TSqlParser::Search_conditionContext *ctx) +{ + if (ctx && ctx->predicate_br().size() > 0) + { + for (auto pred : ctx->predicate_br()) + { + if (pred && pred->predicate() && pred->predicate()->freetext_predicate()) + return true; + if (pred && pred->search_condition()) { + if (check_freetext_predicate(pred->search_condition())) + return true; + } + } + } + return false; +} + +static void post_process_table_source(TSqlParser::Table_source_itemContext *ctx, PLtsql_expr *expr, ParserRuleContext *baseCtx, bool is_freetext_predicate) { for (auto cctx : ctx->table_source_item()) - post_process_table_source(cctx, expr, baseCtx); + post_process_table_source(cctx, expr, baseCtx, is_freetext_predicate); std::string table_name = extractTableName(nullptr, ctx); @@ -5329,6 +6329,19 @@ static void post_process_table_source(TSqlParser::Table_source_itemContext *ctx, } removeCtxStringFromQuery(expr, ctx->join_hint(), baseCtx); } + + // check for freetext predicate CONTAINS() + if(is_freetext_predicate) + { + std::string schema_name = extractSchemaName(nullptr, ctx); + + const char * t_name = downcase_truncate_identifier(table_name.c_str(), table_name.length(), true); + const char * s_name = downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true); + + // check if full-text index exist for the table, if not throw error + if(!check_fulltext_exist(const_cast (s_name), const_cast (t_name))) + throw PGErrorWrapperException(ERROR, ERRCODE_RAISE_EXCEPTION, format_errmsg("Cannot use a CONTAINS or FREETEXT predicate on table or indexed view '%s' because it is not full-text indexed.", table_name.c_str()), getLineAndPos(ctx)); + } } void process_execsql_remove_unsupported_tokens(TSqlParser::Dml_statementContext *ctx, PLtsql_expr_query_mutator *exprMutator) @@ -5629,6 +6642,91 @@ post_process_alter_table(TSqlParser::Alter_tableContext *ctx, PLtsql_stmt_execsq return false; } +std::pair +getTableNameAndSchemaName(TSqlParser::Table_nameContext* ctx) +{ + std::string table_info = ::getFullText(ctx); + std::string table_name = ""; + std::string schema_name = ""; + size_t pos = table_info.find("."); + if (pos != std::string::npos) { + // Extract the schema name before the "." + schema_name = table_info.substr(0, pos); + // Extract the table name after the "." + table_name = table_info.substr(pos + 1); + } else { + // No "." character found, set first to the entire string + table_name = table_info; + } + return std::make_pair(downcase_truncate_identifier(table_name.c_str(), table_name.length(), true), + downcase_truncate_identifier(schema_name.c_str(), schema_name.length(), true)); +} + +PLtsql_stmt * +makeCreateFulltextIndexStmt(TSqlParser::Create_fulltext_indexContext *ctx) +{ + PLtsql_stmt_fulltextindex *stmt = (PLtsql_stmt_fulltextindex *) palloc0(sizeof(PLtsql_stmt_fulltextindex)); + stmt->cmd_type = PLTSQL_STMT_FULLTEXTINDEX; + stmt->lineno = getLineNo(ctx); + stmt->is_create = true; + + if (ctx->table_name()) + { + auto table_info = getTableNameAndSchemaName(ctx->table_name()); + stmt->table_name = pstrdup(table_info.first.c_str()); + stmt->schema_name = pstrdup(table_info.second.c_str()); + } + List *column_name_list = NIL; + if (ctx->fulltext_index_column().size() > 0) + { + for (auto column : ctx->fulltext_index_column()) + { + if (column->TYPE() && column->COLUMN()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'TYPE COLUMN' option is not currently supported in Babelfish", getLineAndPos(column->TYPE())); + else if (column->LANGUAGE()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'LANGUAGE' option is not currently supported in Babelfish", getLineAndPos(column->LANGUAGE())); + else if (column->STATISTICAL_SEMANTICS()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'STATISTICAL_SEMANTICS' option is not currently supported in Babelfish", getLineAndPos(column->STATISTICAL_SEMANTICS())); + else + { + std::string column_name_str = ::getFullText(column->full_column_name()); + char *column_name = pstrdup(downcase_truncate_identifier(column_name_str.c_str(), column_name_str.length(), true)); + column_name_list = lappend(column_name_list, column_name); + } + + } + stmt->column_name = column_name_list; + } + if (ctx->catalog_filegroup_option()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'CATALOG FILEGROUP OPTION' is not currently supported in Babelfish", getLineAndPos(ctx)); + if (ctx->fulltext_with_option().size() > 0) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "'WITH OPTION' is not currently supported in Babelfish", getLineAndPos(ctx)); + if (ctx->id()) + { + std::string index_name = ::getFullText(ctx->id()); + stmt->index_name = pstrdup(downcase_truncate_identifier(index_name.c_str(), index_name.length(), true)); + } + attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); + return (PLtsql_stmt *) stmt; +} + +PLtsql_stmt * +makeDropFulltextIndexStmt(TSqlParser::Drop_fulltext_indexContext *ctx) +{ + PLtsql_stmt_fulltextindex *stmt = (PLtsql_stmt_fulltextindex *) palloc0(sizeof(PLtsql_stmt_fulltextindex)); + stmt->cmd_type = PLTSQL_STMT_FULLTEXTINDEX; + stmt->lineno = getLineNo(ctx); + stmt->is_create = false; + if (ctx->table_name()) + { + auto table_info = getTableNameAndSchemaName(ctx->table_name()); + stmt->table_name = pstrdup(table_info.first.c_str()); + stmt->schema_name = pstrdup(table_info.second.c_str()); + } + attachPLtsql_fragment(ctx, (PLtsql_stmt *) stmt); + return (PLtsql_stmt *) stmt; +} + static bool post_process_create_index(TSqlParser::Create_indexContext *ctx, PLtsql_stmt_execsql *stmt, TSqlParser::Ddl_statementContext *baseCtx) { @@ -6534,3 +7632,78 @@ getIDName(TerminalNode *dq, TerminalNode *sb, TerminalNode *id) return std::string(id->getSymbol()->getText()); } } + +// rewriteDoubleQuotedString() - change double-quoted string to single-quoted +// A double-quoted string must be changed to a single-quoted string +// since PG accepts only single quotes as string delimiters. This requires: +// - change the enclosing quotes to single quotes +// - escape any single quotes in the string by doubling them +// - unescape any double quotes +std::string +rewriteDoubleQuotedString(const std::string strDoubleQuoted) +{ + std::string str = strDoubleQuoted; + + Assert(str.front() == '"'); + Assert(str.back() == '"'); + + // For any embedded single-quotes, these must be escaped by doubling them + for (size_t i = str.find("\'", 1); // start at pos 1: char 0 has the enclosing quote + i != std::string::npos; + i = str.find("\'", i + 2) ) + { + str.replace(i, 1, "''"); // Change single quote to 2 single-quotes + } + + // Now change the enclosing quotes, i.e. from "foo" to 'foo' + // Must do this after embedded single-quote handling above + str.front() = '\''; + str.back() = '\''; + + // For any embedded double-quotes, these must be un-escaped by removing one of the two + for (size_t i = str.find("\"\"", 1); // Start at pos 1: char 0 has the enclosing quote + i != std::string::npos; + i = str.find("\"\"", i + 1) ) + { + str.replace(i, 2, "\""); // Remove one of the double quotes + } + + return str; +} + +// Escape double quotes by doubling them +std::string +escapeDoubleQuotes(const std::string strWithDoubleQuote) +{ + std::string quote = "\""; + std::string str = strWithDoubleQuote; + + // If the string contains embedded quotes, these must be escaped by doubling them + for (size_t i = str.find(quote, 1); // Start at pos 1: char 0 has the enclosing delimiter + i != std::string::npos; + i = str.find(quote, i + 2) ) + { + str.replace(i, 1, quote+quote); // Change quote to 2 quotes + } + + return str; +} + +PLtsql_stmt * +makeChangeDbOwnerStatement(TSqlParser::Alter_authorizationContext *ctx) +{ + PLtsql_stmt_change_dbowner *result = (PLtsql_stmt_change_dbowner *) palloc0(sizeof(*result)); + + result->cmd_type = PLTSQL_STMT_CHANGE_DBOWNER; + result->lineno = getLineNo(ctx); + + // 'table' represents the actual database name in the grammar + std::string db_name_str = stripQuoteFromId(ctx->entity_name()->table); + result->db_name = pstrdup(downcase_truncate_identifier(db_name_str.c_str(), db_name_str.length(), true)); + + // Login name for the new owner + std::string new_owner_name_str = stripQuoteFromId(ctx->authorization_grantee()->id()); + result->new_owner_name = pstrdup(downcase_truncate_identifier(new_owner_name_str.c_str(), new_owner_name_str.length(), true)); + + return (PLtsql_stmt *) result; +} 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..27c6869442 100644 --- a/contrib/babelfishpg_tsql/src/tsqlNodes.h +++ b/contrib/babelfishpg_tsql/src/tsqlNodes.h @@ -5,100 +5,105 @@ #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_CHANGE_DBOWNER, + PLTSQL_STMT_DBCC, + PLTSQL_STMT_GRANTSCHEMA + PLTSQL_STMT_FULLTEXTINDEX } 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.cpp b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp index b74342b373..145eedf35e 100644 --- a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp +++ b/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.cpp @@ -121,12 +121,14 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler // for unsupported DDLs. we'll manage whitelist antlrcpp::Any visitDdl_statement(TSqlParser::Ddl_statementContext *ctx) override; + antlrcpp::Any visitAlter_authorization(TSqlParser::Alter_authorizationContext *ctx) override; // DML antlrcpp::Any visitSelect_statement(TSqlParser::Select_statementContext *ctx) override; 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; @@ -142,14 +144,14 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler antlrcpp::Any visitCreate_contract(TSqlParser::Create_contractContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_CREATE_CONTRACT, "CREATE CONTRACT", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitCreate_queue(TSqlParser::Create_queueContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_CREATE_QUEUE, "CREATE QUEUE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitAlter_queue(TSqlParser::Alter_queueContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_ALTER_QUEUE, "ALTER QUEUE", getLineAndPos(ctx)); return visitChildren(ctx); } - antlrcpp::Any visitKill_statement(TSqlParser::Kill_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_KILL, "KILL", getLineAndPos(ctx)); return visitChildren(ctx); } + antlrcpp::Any visitKill_statement(TSqlParser::Kill_statementContext *ctx) override; antlrcpp::Any visitCreate_message_type(TSqlParser::Create_message_typeContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_CREATE_MESSAGE, "CREATE MESSAGE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitSecurity_statement(TSqlParser::Security_statementContext *ctx) override; antlrcpp::Any visitSetuser_statement(TSqlParser::Setuser_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_SET_USER, "SET USER", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitReconfigure_statement(TSqlParser::Reconfigure_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_RECONFIGURE, "RECONFIGURE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitShutdown_statement(TSqlParser::Shutdown_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_SHUTDOWN, "SHUTDOWN", getLineAndPos(ctx)); return visitChildren(ctx); } - antlrcpp::Any visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_DBCC, "DBCC", getLineAndPos(ctx)); return visitChildren(ctx); } + antlrcpp::Any visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) override; antlrcpp::Any visitBackup_statement(TSqlParser::Backup_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_BACKUP, "BACKUP", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitRestore_statement(TSqlParser::Restore_statementContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_RESTORE, "RESTORE", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitCheckpoint_statement(TSqlParser::Checkpoint_statementContext *ctx) override; @@ -187,19 +189,17 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler } antlrcpp::Any visitTrigger_column_updated(TSqlParser::Trigger_column_updatedContext *ctx) override; // UPDATE() in trigger antlrcpp::Any visitFreetext_function(TSqlParser::Freetext_functionContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_FREETEXT, "FREETEXT", getLineAndPos(ctx)); return visitChildren(ctx); } + antlrcpp::Any visitFreetext_predicate(TSqlParser::Freetext_predicateContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_FREETEXT, "CONTAINS/FREETEXT predicate", &st_escape_hatch_fulltext, getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitOdbc_scalar_function(TSqlParser::Odbc_scalar_functionContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_ODBC_SCALAR_FUNCTION, "ODBC scalar functions", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitPartition_function_call(TSqlParser::Partition_function_callContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_PARTITION_FUNCTION, "partition function", getLineAndPos(ctx)); return visitChildren(ctx); } - antlrcpp::Any visitDefault_expr(TSqlParser::Default_exprContext *ctx) override; antlrcpp::Any visitHierarchyid_coloncolon(TSqlParser::Hierarchyid_coloncolonContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_EXPRESSION_HIERARCHID, "hierarchid", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitOdbc_literal_expr(TSqlParser::Odbc_literal_exprContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_EXPRESSION_ODBC_LITERAL, "odbc literal", getLineAndPos(ctx)); return visitChildren(ctx); } antlrcpp::Any visitDollar_action_expr(TSqlParser::Dollar_action_exprContext *ctx) override { handle(INSTR_UNSUPPORTED_TSQL_EXPRESSION_DOLLAR_ACTION, "$ACTION", getLineAndPos(ctx)); return visitChildren(ctx); } - antlrcpp::Any visitExecute_parameter(TSqlParser::Execute_parameterContext *ctx) override; 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; @@ -234,6 +234,10 @@ class TsqlUnsupportedFeatureHandlerImpl : public TsqlUnsupportedFeatureHandler void checkSupportedGrantStmt(TSqlParser::Grant_statementContext *grant); void checkSupportedRevokeStmt(TSqlParser::Revoke_statementContext *revoke); + + void visitSqlClauses(vector sql_clauses); + void visitSqlClauses(TSqlParser::Sql_clausesContext* option); + }; std::unique_ptr TsqlUnsupportedFeatureHandler::create() @@ -264,6 +268,25 @@ void TsqlUnsupportedFeatureHandlerImpl::handle(PgTsqlInstrMetricType tm_type, co } } +antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitKill_statement(TSqlParser::Kill_statementContext *ctx) +{ + if (ctx->kill_query_notification()) + handle(INSTR_UNSUPPORTED_TSQL_KILL, "KILL with QUERY NOTIFICATION", getLineAndPos(ctx->KILL())); + else if (ctx->kill_stats_job()) + handle(INSTR_UNSUPPORTED_TSQL_KILL, "KILL with STATS JOB", getLineAndPos(ctx->KILL())); + else if (ctx->kill_process()) + { + if (ctx->kill_process()->STATUSONLY()) + handle(INSTR_UNSUPPORTED_TSQL_KILL, "KILL with STATUSONLY", getLineAndPos(ctx->KILL())); + else if (ctx->kill_process()->UOW()) + handle(INSTR_UNSUPPORTED_TSQL_KILL, "KILL with UOW", getLineAndPos(ctx->KILL())); + else if (ctx->kill_process()->char_string()) + handle(INSTR_UNSUPPORTED_TSQL_KILL, "KILL with a session ID string", getLineAndPos(ctx->KILL())); + } + + return visitChildren(ctx); +} + antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitCreate_or_alter_function(TSqlParser::Create_or_alter_functionContext *ctx) { if (ctx->ALTER()) @@ -311,6 +334,11 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitCreate_or_alter_function(T } } + if(ctx->func_body_returns_table()) + visitSqlClauses(ctx->func_body_returns_table()->sql_clauses()); + if(ctx->func_body_returns_scalar()) + visitSqlClauses(ctx->func_body_returns_scalar()->sql_clauses()); + if (ctx->func_body_returns_scalar() && ctx->func_body_returns_scalar()->external_name()) handle(INSTR_UNSUPPORTED_TSQL_ALTER_FUNCTION_EXTERNAL_NAME_OPTION, "EXTERNAL NAME", getLineAndPos(ctx->func_body_returns_scalar()->external_name())); if (ctx->func_body_returns_table_clr() && ctx->func_body_returns_table_clr()->external_name()) @@ -361,6 +389,8 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitCreate_or_alter_procedure( } } + visitSqlClauses(ctx->sql_clauses()); + if (ctx->atomic_proc_body()) handle(INSTR_UNSUPPORTED_TSQL_ALTER_PROCEDURE_ATOMIC_WITH_OPTION, "ATOMIC WITH", getLineAndPos(ctx->atomic_proc_body())); @@ -429,6 +459,8 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitCreate_or_alter_trigger(TS } } + visitSqlClauses(dctx->sql_clauses()); + if (dctx->external_name()) handle(INSTR_UNSUPPORTED_TSQL_DML_TRIGGER_EXTERNAL_NAME_OPTION, "EXERNAL NAME", getLineAndPos(dctx->external_name())); } @@ -450,6 +482,8 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitCreate_or_alter_trigger(TS } } + visitSqlClauses(dctx->sql_clauses()); + if (dctx->external_name()) handle(INSTR_UNSUPPORTED_TSQL_DDL_TRIGGER_EXTERNAL_NAME_OPTION, "EXERNAL NAME", getLineAndPos(dctx->external_name())); } @@ -737,16 +771,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)); + } } } @@ -987,14 +1023,27 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitAlter_login(TSqlParser::Al return visitChildren(ctx); } +antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitAlter_authorization(TSqlParser::Alter_authorizationContext *ctx) +{ + if (!ctx->object_type()) + handle(INSTR_UNSUPPORTED_TSQL_ALTER_AUTHORIZATION, "ALTER AUTHORIZATION on object types other than DATABASE::", getLineAndPos(ctx)); + else { + std::string object_type = ::getFullText(ctx->object_type()); + if (pg_strcasecmp("DATABASE", object_type.c_str()) != 0) + handle(INSTR_UNSUPPORTED_TSQL_ALTER_AUTHORIZATION, "ALTER AUTHORIZATION on object types other than DATABASE::", getLineAndPos(ctx)); + } + + if (ctx->authorization_grantee()->SCHEMA()) + handle(INSTR_UNSUPPORTED_TSQL_ALTER_AUTHORIZATION, "ALTER AUTHORIZATION TO SCHEMA OWNER", getLineAndPos(ctx)); + + if (ctx->entity_name()->DOT().size() > 0) + handle(INSTR_UNSUPPORTED_TSQL_ALTER_AUTHORIZATION, "ALTER AUTHORIZATION with multi-part database name", getLineAndPos(ctx)); + + return visitChildren(ctx); +} + antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDdl_statement(TSqlParser::Ddl_statementContext *ctx) { - if (ctx->alter_user()) - { - auto alter_user = ctx->alter_user(); - if (alter_user->loginame) - handle(INSTR_UNSUPPORTED_TSQL_UNKNOWN_DDL, "ALTER USER WITH LOGIN", getLineAndPos(ctx)); - } if (ctx->create_user()) { auto create_user = ctx->create_user(); @@ -1007,12 +1056,17 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDdl_statement(TSqlParser:: if (create_user->WITHOUT()) handle(INSTR_UNSUPPORTED_TSQL_UNKNOWN_DDL, "CREATE USER WITHOUT LOGIN", getLineAndPos(ctx)); } + if(ctx->alter_fulltext_index()) + { + handle(INSTR_UNSUPPORTED_TSQL_UNKNOWN_DDL, "ALTER FULLTEXT INDEX", getLineAndPos(ctx)); + } /* * We have more than 100 DDLs but support a few of them. * manage the whitelist here. * Please keep the order in grammar file. */ - if (ctx->alter_database() + if (ctx->alter_authorization() + || ctx->alter_database() || ctx->alter_db_role() || ctx->alter_fulltext_index() || ctx->alter_index() @@ -1050,6 +1104,8 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDdl_statement(TSqlParser:: || ctx->drop_user() || ctx->drop_view() || ctx->truncate_table() + || ctx->enable_trigger() + || ctx->disable_trigger() ) { // supported DDL or DDL which need special handling @@ -1092,6 +1148,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); } @@ -1100,6 +1160,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()) @@ -1113,9 +1176,19 @@ 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) { return visitChildren(ctx); @@ -1154,8 +1227,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)); @@ -1207,6 +1278,31 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitTransaction_statement(TSql return visitChildren(ctx); } +antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDbcc_statement(TSqlParser::Dbcc_statementContext *ctx) +{ + + if (ctx->dbcc_command()) + { + if (ctx->dbcc_command()->ID()) + { + throw PGErrorWrapperException(ERROR, ERRCODE_SYNTAX_ERROR, + "Incorrect DBCC statement. Check the documentation for the " + "correct DBCC syntax and options.", + getLineAndPos(ctx->dbcc_command())); + } + else + { + std::string dbcc_cmd = ::getFullText(ctx->dbcc_command()); + std::transform(dbcc_cmd.begin(), dbcc_cmd.end(), dbcc_cmd.begin(), ::toupper); + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, + format_errmsg("DBCC %s is not currently supported in Babelfish", + dbcc_cmd.c_str()), + getLineAndPos(ctx->dbcc_command())); + } + } + return visitChildren(ctx); +} + antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitSecurity_statement(TSqlParser::Security_statementContext *ctx) { if (ctx->execute_as_statement()) @@ -1237,8 +1333,6 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitCheckpoint_statement(TSqlP antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitTable_source_item(TSqlParser::Table_source_itemContext *ctx) { - if (ctx->PIVOT()) - handle(INSTR_UNSUPPORTED_TSQL_PIVOT, ctx->PIVOT()); if (ctx->UNPIVOT()) handle(INSTR_UNSUPPORTED_TSQL_UNPIVOT, ctx->UNPIVOT()); @@ -1301,14 +1395,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()) @@ -1317,21 +1403,6 @@ antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitAggregate_windowed_functio return visitChildren(ctx); } -antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitDefault_expr(TSqlParser::Default_exprContext *ctx) -{ - TSqlParser::Expression_listContext *pctx = dynamic_cast(ctx->parent); - if (!pctx || dynamic_cast(pctx->parent) == nullptr) /* if DEFAULT expression is used for VALUES ..., accept it */ - handle(INSTR_UNSUPPORTED_TSQL_EXPRESSION_DEFAULT, ctx->DEFAULT()); - return visitChildren(ctx); -} - -antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitExecute_parameter(TSqlParser::Execute_parameterContext *ctx) -{ - if (ctx->DEFAULT()) - handle(INSTR_UNSUPPORTED_TSQL_EXECUTE_PARAMETER_DEFAULT, ctx->DEFAULT()); - return visitChildren(ctx); -} - antlrcpp::Any TsqlUnsupportedFeatureHandlerImpl::visitTrigger_column_updated(TSqlParser::Trigger_column_updatedContext *ctx) { if (!is_inside_trigger && pltsql_curr_compile->fn_is_trigger == PLTSQL_NOT_TRIGGER){ @@ -1366,7 +1437,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()) { @@ -1377,14 +1448,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()) @@ -1471,7 +1534,6 @@ const char *unsupported_sp_procedures[] = { "sp_add_data_file_recover_suspect_db", "sp_add_log_file_recover_suspect_db", "sp_addextendedproc", - "sp_addextendedproperty", "sp_addmessage", "sp_addtype", "sp_addumpdevice", @@ -1507,7 +1569,6 @@ const char *unsupported_sp_procedures[] = { "sp_detach_db", "sp_dropdevice", "sp_dropextendedproc", - "sp_dropextendedproperty", "sp_dropmessage", "sp_droptype", "sp_getbindtoken", @@ -1535,16 +1596,13 @@ const char *unsupported_sp_procedures[] = { "sp_renamedb", "sp_resetstatus", "sp_sequence_get_range", - "sp_serveroption", "sp_setnetname", "sp_settriggerorder", "sp_spaceused", "sp_tableoption", "sp_unbindefault", "sp_unbindrule", - "sp_updateextendedproperty", "sp_validname", - "sp_who", /* Security */ "sp_add_trusted_assembly", @@ -1557,7 +1615,6 @@ const char *unsupported_sp_procedures[] = { "sp_approlepassword", "sp_audit_write", "sp_change_users_login", - "sp_changedbowner", "sp_changeobjectowner", "sp_control_dbmasterkey_password", "sp_dbfixedrolepermission", @@ -1589,7 +1646,6 @@ const char *unsupported_sp_procedures[] = { "sp_revokelogin", "sp_setapprole", "sp_srvrolepermission", - "sp_testlinkedserver", "sp_unsetapprole", "sp_validatelogins", "sp_verify_database_ledger", @@ -1648,7 +1704,6 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran unsupported_feature = "GRANT PERMISSION " + perm->getText(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(perm)); } - } } @@ -1656,7 +1711,9 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran { auto perm_obj = grant->permission_object(); auto obj_type = perm_obj->object_type(); - if (obj_type && !obj_type->OBJECT()) + if (grant->ALL() && obj_type && obj_type->SCHEMA()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "The all permission has been deprecated and is not available for this class of entity.", getLineAndPos(grant)); + if (obj_type && !(obj_type->OBJECT() || obj_type->SCHEMA())) { unsupported_feature = "GRANT ON " + obj_type->getText(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(obj_type)); @@ -1667,6 +1724,39 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedGrantStmt(TSqlParser::Gran handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, "GRANT AS", getLineAndPos(grant->AS())); } +void TsqlUnsupportedFeatureHandlerImpl::visitSqlClauses(vector sql_clauses) +{ + for (auto option : sql_clauses) + { + visitSqlClauses(option); + } +} + +void TsqlUnsupportedFeatureHandlerImpl::visitSqlClauses(TSqlParser::Sql_clausesContext* option) +{ + if(option->another_statement() && option->another_statement()->use_statement()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "a USE database statement is not allowed in a procedure, function or trigger.", getLineAndPos(option)); + + if(option->cfl_statement()) + { + if(option->cfl_statement()->block_statement()) + visitSqlClauses(option->cfl_statement()->block_statement()->sql_clauses()); + + if(option->cfl_statement()->if_statement()) + visitSqlClauses(option->cfl_statement()->if_statement()->sql_clauses()); + + if(option->cfl_statement()->while_statement()) + visitSqlClauses(option->cfl_statement()->while_statement()->sql_clauses()); + if(option->cfl_statement()->try_catch_statement()) + { + if(option->cfl_statement()->try_catch_statement()->try_block()) + visitSqlClauses(option->cfl_statement()->try_catch_statement()->try_block()->sql_clauses()); + + if(option->cfl_statement()->try_catch_statement()->catch_block()) + visitSqlClauses(option->cfl_statement()->try_catch_statement()->catch_block()->sql_clauses()); + } + } +} void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Revoke_statementContext *revoke) { std::string unsupported_feature; @@ -1708,7 +1798,6 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Rev unsupported_feature = "REVOKE PERMISSION " + perm->getText(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(perm)); } - } } @@ -1716,7 +1805,9 @@ void TsqlUnsupportedFeatureHandlerImpl::checkSupportedRevokeStmt(TSqlParser::Rev { auto perm_obj = revoke->permission_object(); auto obj_type = perm_obj->object_type(); - if (obj_type && !obj_type->OBJECT()) + if (revoke->ALL() && obj_type && obj_type->SCHEMA()) + throw PGErrorWrapperException(ERROR, ERRCODE_FEATURE_NOT_SUPPORTED, "The all permission has been deprecated and is not available for this class of entity.", getLineAndPos(revoke)); + if (obj_type && !(obj_type->OBJECT() || obj_type->SCHEMA())) { unsupported_feature = "REVOKE ON " + obj_type->getText(); handle(INSTR_UNSUPPORTED_TSQL_REVOKE_STMT, unsupported_feature.c_str(), getLineAndPos(obj_type)); diff --git a/contrib/babelfishpg_tsql/src/tsql_analyze.c b/contrib/babelfishpg_tsql/src/tsql_analyze.c index 79ef852dc9..319f62a972 100644 --- a/contrib/babelfishpg_tsql/src/tsql_analyze.c +++ b/contrib/babelfishpg_tsql/src/tsql_analyze.c @@ -9,11 +9,15 @@ #include "postgres.h" #include "catalog/namespace.h" +#include "nodes/makefuncs.h" #include "nodes/nodes.h" #include "nodes/parsenodes.h" #include "nodes/pg_list.h" #include "nodes/primnodes.h" #include "parser/parse_clause.h" +#include "parser/parse_coerce.h" +#include "parser/parse_collate.h" +#include "parser/parsetree.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -36,39 +40,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 +81,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 +109,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 +143,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 +167,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 +179,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 +192,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 +234,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 +262,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 +283,228 @@ 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; + } + 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; + } + default: + return; + } +} + +/* + * Prior to analysis of the setop (i.e. UNION) tree, move the ORDER BY clause + * down to the leftmost SELECT statement. This is to account for T-SQL behavior, + * where UNION ORDER BY names are resolved according to the leftmost select. + */ +void +pre_transform_setop_tree(SelectStmt *stmt, SelectStmt *leftmostSelect) +{ + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + leftmostSelect->sortClause = stmt->sortClause; +} + +/* + * fix_setop_typmods will backtrack through the SetOperationTree to + * fix the types of char, nchar, varchar, and nvarchar + * + * We do this after the tree has already been transformed so we may + * compare all expressions in the same column at once. PG only compares + * two at a time, leading to issues for example if both expressions are NULL. + * + * Then, we update the original expressions as well as the top-level target list's + * expressions with the correct type and typmod. + */ +static void +fix_setop_typmods(ParseState *pstate, Query *qry) +{ + List *setOpTreeStack = list_make1(qry->setOperations); + List *setOpNodes = NIL; + List *collist_list = NIL; + List *topColTypes = NIL; + List *topColTypmods = NIL; + List *topColCollations = NIL; + ListCell *collistl, *setopsl, *toptlistl; + Oid common_type, common_collation; + int32 common_typmod; + + /* Iterate through the SetOpTree. For each column, save each expression + * in that column to a list. That is, for select a, b, c union select x, y, x, + * give [a, x], [b, y], [c, z] */ + while (setOpTreeStack) + { + Node *setOp = llast(setOpTreeStack); + setOpTreeStack = list_delete_last(setOpTreeStack); + + if (IsA(setOp, SetOperationStmt)) { - 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; + SetOperationStmt *op = (SetOperationStmt *) setOp; + setOpNodes = lappend(setOpNodes, op); + setOpTreeStack = lappend(setOpTreeStack, op->rarg); + setOpTreeStack = lappend(setOpTreeStack, op->larg); + } else if (IsA(setOp, RangeTblRef)) + { + RangeTblRef *rtref = (RangeTblRef*)setOp; + RangeTblEntry *rte; + List *targetList; + ListCell *tlistl, *collistl; + + if (rtref->rtindex <= 0 || rtref->rtindex > list_length(pstate->p_rtable)) + elog(ERROR, "invalid RangeTblRef %d", rtref->rtindex); + + rte = rt_fetch(rtref->rtindex, pstate->p_rtable); + targetList = rte->subquery->targetList; + + if(collist_list == NIL) + { + foreach(tlistl, targetList) + { + TargetEntry *tle = (TargetEntry*) lfirst(tlistl); + collist_list = lappend(collist_list, list_make1(tle)); + } + } + else + { + forboth(tlistl, targetList, collistl, collist_list) + { + List *collist = (List*) lfirst(collistl); + TargetEntry *tle = (TargetEntry*) lfirst(tlistl); + collist = lappend(collist, tle); + } + } } - case CMD_DELETE: + } + + /* For each of the column lists built above, determine the resulting + * common_type and typmod. Update both the expressions and the toplevel + * targetlist with the correct types. */ + forboth(collistl, collist_list, + toptlistl, qry->targetList) + { + List *col_tles = lfirst(collistl); + List *col_exprs = NIL; + ListCell *lc; + TargetEntry *top_tle = (TargetEntry*) lfirst(toptlistl); + Var *top_expr = (Var*) top_tle->expr; + + + foreach(lc, col_tles) { - 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); + TargetEntry *tle = (TargetEntry*) lfirst(lc); + col_exprs = lappend(col_exprs, (Node*)tle->expr); + } + + common_type = select_common_type(pstate, col_exprs, "UNION/INTERSECT/EXCEPT", NULL); + common_typmod = select_common_typmod(pstate, col_exprs, common_type); + topColTypes = lappend_oid(topColTypes, common_type); + topColTypmods = lappend_int(topColTypmods, common_typmod); + + list_free(col_exprs); + col_exprs = NIL; + + foreach(lc, col_tles) + { + TargetEntry *tle = (TargetEntry*) lfirst(lc); + Node *expr = (Node*) tle->expr; + Expr *coerced_expr; + coerced_expr = (Expr*) coerce_to_target_type(pstate, expr, exprType(expr), + common_type, common_typmod, COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, -1); + if(coerced_expr) /* Only coerce to target if implicit cast exists*/ + tle->expr = coerced_expr; + col_exprs = lappend(col_exprs, (Node*)tle->expr); + } + + common_collation = select_common_collation(pstate, col_exprs, false); + topColCollations = lappend_oid(topColCollations, common_collation); + + Assert(IsA(top_expr, Var)); + top_tle->expr = (Expr*) makeVar(top_expr->varno, + top_expr->varattno, + common_type, + common_typmod, + common_collation, + 0); + list_free(col_exprs); + list_free(col_tles); + } + + foreach(setopsl, setOpNodes) + { + SetOperationStmt *sostmt = (SetOperationStmt*) lfirst(setopsl); + sostmt->colTypes = topColTypes; + sostmt->colTypmods = topColTypmods; + sostmt->colCollations = topColCollations; + } + + list_free(collist_list); +} + +/* + * This hook is called for set operations after the tree has been analyzed + * and before any ORDER BYs are handled + * + * First, all target lists are re-processed to reflect the + * correct types and typmods + * + * To support sort clauses with table names and aliases, we moved the sortclause + * into the leftmost select in pre_transform_setop_tree. Now, rebuild + * the sort clause using column index numbers. This will ensure the correct + * sort operators are used if the column's type has changed. + */ +void +pre_transform_setop_sort_clause(ParseState *pstate, Query *qry, List *sortClause, Query *leftmostQuery) +{ + ListCell *leftsort_lc, *topsort_lc, *leftlist_lc; + + if (sql_dialect != SQL_DIALECT_TSQL) + return; + + fix_setop_typmods(pstate, qry); + + forboth(leftsort_lc, leftmostQuery->sortClause, topsort_lc, sortClause) + { + SortGroupClause *left_sortcl = (SortGroupClause*) lfirst(leftsort_lc); + SortBy *top_sortby = (SortBy*) lfirst(topsort_lc); + A_Const *n = makeNode(A_Const); + + /* Find the index of the corresponding TLE */ + foreach(leftlist_lc, leftmostQuery->targetList) + { + TargetEntry *tle = (TargetEntry*) lfirst(leftlist_lc); + + if (tle->ressortgroupref != left_sortcl->tleSortGroupRef) + continue; + + /* Throw an error if the entry was not explicitly included in the select list */ + if (tle->resjunk) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator."), + parser_errposition(pstate, exprLocation((Node*)tle->expr)))); + + n->val.ival.type = T_Integer; + n->val.ival.ival = foreach_current_index(leftlist_lc) + 1; + n->location = -1; break; } - default: - return; + top_sortby->node = (Node*) n; } -} \ No newline at end of file + + leftmostQuery->sortClause = NIL; +} diff --git a/contrib/babelfishpg_tsql/src/tsql_analyze.h b/contrib/babelfishpg_tsql/src/tsql_analyze.h index fd916844b5..c2883b2184 100644 --- a/contrib/babelfishpg_tsql/src/tsql_analyze.h +++ b/contrib/babelfishpg_tsql/src/tsql_analyze.h @@ -13,5 +13,7 @@ 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 pre_transform_setop_tree(SelectStmt *stmt, SelectStmt *leftmostSelect); +extern void pre_transform_setop_sort_clause(ParseState *pstate, Query *qry, List *sortClause, Query *leftmostQuery); -#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..360ae65d37 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/forjson.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/forjson.c @@ -15,122 +15,149 @@ #include "parser/parser.h" #include "utils/builtins.h" #include "utils/json.h" +#include "utils/jsonb.h" #include "utils/syscache.h" #include "utils/typcache.h" +#include "utils/hsearch.h" #include "catalog/pg_type.h" #include "catalog/namespace.h" #include "tsql_for.h" -static void tsql_row_to_json(StringInfo state, Datum record, bool include_null_values); +#define TABLE_SIZE 100 + +// For holding information regarding the state of the FOR JSON call +// Necessary to pass information regarding root_name & without_array-wrappers +// to ffunc. +typedef struct { + bool without_array_wrapper; + char *root_name; + JsonbValue* jsonbArray; +} forjson_state; + +// Entry struct for use in HashTable +typedef struct { + char path[NAMEDATALEN]; + JsonbValue *value; + JsonbValue *parent; + int idx; +} JsonbEntry; + +static void tsql_row_to_json(JsonbValue* jsonbArray, Datum record, bool include_null_values); + +static char** determine_parts(const char* str, int *num); + +static char* build_key(char **parts, int currentIdx); + +static JsonbValue* create_json(char *part, JsonbValue* val, int *idx); + +static void insert_existing_json(JsonbValue *exists, JsonbValue* parent, JsonbValue *val, int idx, char *key); PG_FUNCTION_INFO_V1(tsql_query_to_json_sfunc); Datum tsql_query_to_json_sfunc(PG_FUNCTION_ARGS) { - StringInfo state; + forjson_state *state; + JsonbValue *jsonbArray; + Datum record; - int mode; + 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); include_null_values = PG_GETARG_BOOL(3); if (PG_ARGISNULL(0)) { - /* first time setup */ - state = makeStringInfo(); + // First time setup for struct & JsonBValue + state = (forjson_state *) palloc(sizeof(forjson_state)); + + jsonbArray = palloc(sizeof(JsonbValue)); + jsonbArray->type = jbvArray; + jsonbArray->val.array.nElems = 0; + jsonbArray->val.array.rawScalar = false; + jsonbArray->val.array.elems = (JsonbValue *) palloc(sizeof(JsonbValue)); + + // Populate the struct 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 */ - appendStringInfo(state, "<{\"%s\":[", root_name); - else if (!without_array_wrapper) - appendStringInfoChar(state,'['); + + state->jsonbArray = jsonbArray; + state->without_array_wrapper = without_array_wrapper; + state->root_name = root_name; } else { - state = (StringInfo) PG_GETARG_POINTER(0); - appendStringInfoChar(state, ','); + state = (forjson_state*) PG_GETARG_POINTER(0); + jsonbArray = state->jsonbArray; } 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 */ - tsql_row_to_json(state, record, include_null_values); + tsql_row_to_json(jsonbArray, record, include_null_values); break; default: /* 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); - PG_RETURN_POINTER(state); } -PG_FUNCTION_INFO_V1(tsql_query_to_json_ffunc); - -Datum -tsql_query_to_json_ffunc(PG_FUNCTION_ARGS) +// Main row to json function. +// Creates a Jsonb row object, processes the row, determines if it should be inserted as a nested json object +// inserts json object to row and then into the main jsonbArray. +static void +tsql_row_to_json(JsonbValue* jsonbArray, Datum record, bool include_null_values) { - StringInfo res = makeStringInfo(); - 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 */ - { - appendStringInfoString(res, state+1); - appendStringInfoString(res, "]}"); - } - else - { - appendStringInfoString(res, state); - } - PG_RETURN_TEXT_P(cstring_to_text_with_len(res->data, res->len)); -} + // HashTable + HTAB *jsonbHash; + HASHCTL ct; + + // JsonbValue for the row + JsonbValue *jsonbRow; -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; td = DatumGetHeapTupleHeader(record); @@ -143,54 +170,81 @@ 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,'{'); + + // Initialize the JsonbValue for the row + jsonbRow = palloc(sizeof(JsonbValue)); + jsonbRow->type = jbvObject; + jsonbRow->val.object.nPairs = 0; + jsonbRow->val.object.pairs = palloc(sizeof(JsonbPair) * tupdesc->natts); + + // Initialize the hashTable to hold information regarding the nested json objects within the row + memset(&ct, 0, sizeof(ct)); + ct.keysize = NAMEDATALEN; + ct.entrysize = sizeof(JsonbEntry); + jsonbHash = hash_create("JsonbHash", TABLE_SIZE, &ct, HASH_ELEM | HASH_STRINGS); /* 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; + // Pair object that holds key-value + JsonbValue *key; + JsonbValue *value; + JsonbPair *jsonbPair; + + // Used for nested json Objects + JsonbEntry *hashEntry; + JsonbValue *nestedVal; + JsonbValue *current; + char **parts; + int num; + bool found; + char *hashKey; + + 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 +254,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 +297,278 @@ 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; } } + + // Check for NULL + if (isnull && include_null_values) { + value = palloc(sizeof(JsonbValue)); + value->type=jbvNull; + } + else { + // Extract the colummn value in the correct format + value = palloc(sizeof(JsonbValue)); + jsonb_get_value(colval, isnull, value, datatype_oid); + value = &value->val.array.elems[0]; + } + + // Determine if the value should be inserted as a nested json object + parts = determine_parts(colname, &num); + nestedVal = value; - appendStringInfoString(state,sep); - sep = ","; - tsql_json_build_object(state, CStringGetDatum(colname), colval, datatype_oid, isnull); + found = false; + if (num > 1) { + for (int i = num - 1; i >= 0; i--) { + hashKey = build_key(parts, i); + // Check if the current key exists in the hashTable + hashEntry = (JsonbEntry *) hash_search(jsonbHash, hashKey, HASH_FIND, &found); + + // If it exists, we insert the value into the existing JsonbValue and break out of the loop + if (hashEntry) { + // function call + current = hashEntry->value; + insert_existing_json(current, hashEntry->parent, nestedVal, hashEntry->idx, colname); + pfree(hashKey); + break; + } + + // If it does not exist + hashEntry = (JsonbEntry *) hash_search(jsonbHash, (void *) hashKey, HASH_ENTER, NULL); + strlcpy(hashEntry->path, hashKey, NAMEDATALEN); + hashEntry->value = nestedVal; + nestedVal = create_json(parts[i], nestedVal, &hashEntry->idx); + + // if the nested json is not at the jsonbRow level + if (i != 0) + hashEntry->parent = nestedVal; + else { + hashEntry->parent = jsonbRow; + hashEntry->idx = jsonbRow->val.object.nPairs; + } + + pfree(hashKey); + } + + // Already inserted into existing json object (nested) + if (found) + continue; + + // JsonbValue was created in loop, insert and update structure. + jsonbRow->val.object.pairs[jsonbRow->val.object.nPairs] = nestedVal->val.object.pairs[0]; + jsonbRow->val.object.nPairs++; + } + + else { + // Increment nPairs in the row if it isnt inserted into an already existing json object. + jsonbRow->val.object.nPairs++; + colname = parts[0]; + + // Allocate memory for key and create it + key = palloc(sizeof(JsonbValue)); + key->type = jbvString; + key->val.string.len = strlen(colname); + key->val.string.val = pstrdup(colname); + + // Create JsonbPair + jsonbPair = palloc(sizeof(JsonbPair)); + jsonbPair->key = *key; + jsonbPair->value = *nestedVal; + + // Assign it to the JsonbValue Row + jsonbRow->val.object.pairs[jsonbRow->val.object.nPairs - 1] = *jsonbPair; + } } - appendStringInfoChar(state,'}'); + + // Add the jsonb row to the jsonbArray + jsonbArray->val.array.nElems++; + jsonbArray->val.array.elems = (JsonbValue *) repalloc(jsonbArray->val.array.elems, sizeof(JsonbValue) * (jsonbArray->val.array.nElems)); + jsonbArray->val.array.elems[jsonbArray->val.array.nElems - 1] = *jsonbRow; + ReleaseTupleDesc(tupdesc); } + +PG_FUNCTION_INFO_V1(tsql_query_to_json_ffunc); + +Datum +tsql_query_to_json_ffunc(PG_FUNCTION_ARGS) +{ + forjson_state *state; + JsonbValue *res; + Jsonb *jsonOut; + StringInfo resStr; + + // Only used if a root_name is given + JsonbValue *root; + JsonbValue *key; + + // Get the processed JsonbValue array + state = (forjson_state*) PG_GETARG_POINTER(0); + resStr = makeStringInfo(); + + if (state->root_name) { + + // Key jsonBValue to store the root name + key = palloc(sizeof(JsonbValue)); + key->type = jbvString; + key->val.string.len = strlen(state->root_name); + key->val.string.val = state->root_name; + + // Root JsonbValue where the key is the root name and value is the processed jsonbVal array + root = palloc(sizeof(JsonbValue)); + root->type = jbvObject; + root->val.object.nPairs = 1; + root->val.object.pairs = (JsonbPair *) palloc(sizeof(JsonbPair)); + root->val.object.pairs[0].key = *key; + root->val.object.pairs[0].value = *state->jsonbArray; + + // Update the processed jsonbArray + state->jsonbArray = root; + } + + // Convert JsonbValue to StringInfo for array wrapper check and to return + res = state->jsonbArray; + jsonOut = JsonbValueToJsonb(res); + JsonbToCString(resStr, &jsonOut->root, 0); + + // if without array wrappers is true, remove the array wrappers + if (state->without_array_wrapper) { + if (resStr->data[0] == '[') { + resStr->data++; + resStr->len--; + } + if (resStr->data[resStr->len - 1] == ']') { + resStr->data[resStr->len - 1] = '\0'; + resStr->len--; + } + } + + PG_RETURN_TEXT_P(cstring_to_text_with_len(resStr->data, resStr->len)); +} + +// Function to determine how many nested json objects a column requires +// Splits a string into an array of strings by the "." +static char** +determine_parts(const char* str, int* num) +{ + int i; + char **parts; + char *copy_str; + char *token; + + // Determine how many parts there are (words seperated by ".") + *num = 1; + for (i = 0; str[i]; i++) { + if (str[i] == '.') + (*num)++; + } + + // Create a string array to hold each indiviual word + parts = (char **) palloc(sizeof(char *) * (*num + 1)); + copy_str = pstrdup(str); + token = strtok(copy_str, "."); + i = 0; + while (token != NULL) { + parts[i++] = pstrdup(token); + token = strtok(NULL, "."); + } + + parts[i] = NULL; + pfree(copy_str); + return parts; + +} + +// Function to build a key to use to search in the Hashtable +// Uses the parts** created from determine_parts to build a string +// that is used as a key/path. +static char* +build_key(char **parts, int currentIdx) +{ + StringInfo str; + str = makeStringInfo(); + + // Build a string up to the current path + for (int i = 0; i <= currentIdx; i++) { + appendStringInfoString(str, parts[i]); + if (i < currentIdx) { + appendStringInfoChar(str, '.'); + } + } + + return str->data; +} + +// Function to create the nested json output for a col if required +// Used when created nested json objects +static JsonbValue* +create_json(char *part, JsonbValue* val, int *idx) +{ + JsonbValue *obj; + JsonbValue *key; + JsonbPair *pair; + + // Create key + key = palloc(sizeof(JsonbValue)); + key->type = jbvString; + key->val.string.len = strlen(part); + key->val.string.val = pstrdup(part); + + // Create pair to hold key and value + pair = palloc(sizeof(JsonbPair)); + pair->key = *key; + pair->value = *val; + + // If we are not inserting into an already existing json object + + obj = palloc(sizeof(JsonbValue)); + obj->type = jbvObject; + obj->val.object.nPairs = 1; + obj->val.object.pairs = palloc(sizeof(JsonbPair)); + + + obj->val.object.pairs[obj->val.object.nPairs - 1] = *pair; + *idx = obj->val.object.nPairs - 1; + return obj; + +} + +// Function to append into existing JsonbValue +// Used when the path to insert a json object is already found in the HashTable. +static void +insert_existing_json(JsonbValue *current, JsonbValue* parent, JsonbValue *nestedVal, int idx, char *key) +{ + JsonbPair* newPairs; + // Make sure both current and nestedVal are non-null and are objects + if (!current || !nestedVal || current->type != jbvObject || nestedVal->type != jbvObject) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Property %s cannot be generated in JSON output due to a conflict with another column name or alias. Use different names and aliases for each column in SELECT list.", key))); + } + + // Allocate space for the new pairs + newPairs = (JsonbPair *) repalloc( + current->val.object.pairs, + sizeof(JsonbPair) * (current->val.object.nPairs + nestedVal->val.object.nPairs) + ); + + // Append the pairs from nestedVal to the new pair array + for (int i = 0; i < nestedVal->val.object.nPairs; i++) { + newPairs[current->val.object.nPairs + i] = nestedVal->val.object.pairs[i]; + } + + // Point the current's pairs to the newPairs + current->val.object.pairs = newPairs; + + // Update the pair count + current->val.object.nPairs += nestedVal->val.object.nPairs; + + // update parent pointer + parent->val.object.pairs[idx].value = *current; +} diff --git a/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c b/contrib/babelfishpg_tsql/src/tsql_for/forjson_old.c index b29033b84d..80c71e3c20 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,12 +187,13 @@ 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), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); result = makeStringInfo(); @@ -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..1472f82fd7 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) @@ -211,21 +225,22 @@ tsql_row_to_xml_raw(StringInfo state, Datum record, const char* element_name, bo } } appendStringInfoString(state, "/>"); + ReleaseTupleDesc(tupdesc); } /* * 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 +254,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,73 +293,81 @@ 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') appendStringInfo(state, "", element_name); + ReleaseTupleDesc(tupdesc); } 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..550617e441 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,14 +212,14 @@ 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", - (superuser() ? PGC_SUSET : PGC_USERSET), + GUC_CONTEXT_CONFIG, PGC_S_SESSION, GUC_ACTION_SAVE, true, 0, false); result = makeStringInfo(); @@ -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..6c2fc87b3f 100644 --- a/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.c +++ b/contrib/babelfishpg_tsql/src/tsql_for/tsql_for.c @@ -17,10 +17,17 @@ void tsql_for_datetime_format(StringInfo format_output, const char *outputstr) { - char *date; - char *spaceptr = strstr(outputstr, " "); - int len; + char *date; + char *spaceptr; + int len; + /* if we receive a null value, set the output as an empty string */ + if(outputstr == NULL) { + appendStringInfoChar(format_output, '\0'); + return; + } + + spaceptr = strstr(outputstr, " "); len = spaceptr - outputstr; date = palloc(len + 1); strncpy(date, outputstr, len); @@ -39,9 +46,20 @@ 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; + int len; + + /* if we receive a null value, set the output as an empty string */ + if(str == NULL) { + appendStringInfoChar(format_output, '\0'); + return; + } + + spaceptr = strstr(str, " "); /* append date part of string */ len = spaceptr - str; @@ -59,7 +77,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 */ diff --git a/contrib/babelfishpg_unit/Makefile b/contrib/babelfishpg_unit/Makefile new file mode 100644 index 0000000000..214f50ed4d --- /dev/null +++ b/contrib/babelfishpg_unit/Makefile @@ -0,0 +1,12 @@ +MODULE_big = babelfishpg_unit +EXTENSION = babelfishpg_unit # the extension's name +DATA = babelfishpg_unit--1.0.0.sql # script file to install +OBJS = $(SRCS:.c=.o) # object files + + # source code files +SRCS = babelfishpg_unit.c test_money.c \ + +# for posgres build +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) diff --git a/contrib/babelfishpg_unit/README.md b/contrib/babelfishpg_unit/README.md new file mode 100644 index 0000000000..9bdd5c2b76 --- /dev/null +++ b/contrib/babelfishpg_unit/README.md @@ -0,0 +1,73 @@ +# Babelfish Unit Test Framework + +Babelfish has introduced a new extension named babelfishpg_unit which enables us to run unit tests. Please follow the [build instructions](../../contrib/README.md) to build and install the babelfishpg_unit extension. + +To maintain a well-organized structure, the directory layout will be as follows: + +- babelfish_extensions + - contrib + - babelfishpg_common + - babelfishpg_money + - babelfishpg_tsql + - babelfishpg_tds + - babelfishpg_unit + - Makefile + - babelfishpg_unit.control + - babelfishpg_unit--1.0.0.sql + - babelfishpg_unit.c + - babelfishpg_unit.h + - test_1.c + - test_2.c + +## How to add unit tests for babelfish? + +- To add a new test to the existing framework, within the framework's directory, create a new .c file and name it according to the test we want to add (e.g., test_1.c). Add the function in the file which is to be tested. + - Declare the function you want to test as extern in babelfishpg_unit.h. Eg: + ``` + extern TestResult* test_int4_fixeddecimal_ge(void) + ``` + - Metadata for each test function is added as a row in the tests array, containing the necessary information for the test. This tests array is located in babelfishpg_unit.c. Eg: + ``` + TestInfo tests[]= + { + {&test_int4_fixeddecimal_ge, true, "GreaterThanOrEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + }; + ``` + - Return type of all functions which are to be tested must be TestInfo*. + - Every function should have some expected and obtained output. One should use TEST_ASSERT_TESTCASE(expected == obtained, testResult) first and then TEST_ASSERT(expected == obtained, testResult) to obtain the status of a test. In the TEST_ASSERT_TESTCASE marco, we only set the result field of TestResult struct to true/false based on result. In TEST_ASSERT, we decide whether all the tests have passed or not. Eg: + ``` + TestResult* test_int4_fixeddecimal_ge(void) + { + /* + * This function checks whether val1 is greater than or equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] >= val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; + } + ``` + + - If you want to put any custom message for any test in the output table, use : + - snprintf(testResult->message, MAX_TEST_MESSAGE_LENGTH, "%s", errorData->message); + - This will fill the message column with expected message. When the tests are run, if the condition is met, then you will observe the same message corresponding to that text. + + - If there is any ASSERTION error and TEST_ASSERT_TESTCASE and TEST_ASSERT macros are used to check the condition, then message column will be filled with the error message providing the line where the assertion failed. + diff --git a/contrib/babelfishpg_unit/babelfishpg_unit--1.0.0.sql b/contrib/babelfishpg_unit/babelfishpg_unit--1.0.0.sql new file mode 100644 index 0000000000..c8ae1e9375 --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit--1.0.0.sql @@ -0,0 +1,14 @@ +--complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION IF NOT EXISTS babelfishpg_unit" to load this file. \quit + +-- Invoke all tests +CREATE OR REPLACE FUNCTION babelfishpg_unit.babelfishpg_unit_run_tests() RETURNS +TABLE(TEST_NAME text, STATUS text, MESSAGE text, RUNTIME bigint, ENABLED text) +as 'babelfishpg_unit', 'babelfishpg_unit_run_tests' +LANGUAGE C IMMUTABLE STRICT; + +-- Invoke specific tests by passing test_name, cateogry_name or JIRA associated with +CREATE OR REPLACE FUNCTION babelfishpg_unit.babelfishpg_unit_run_tests(VARIADIC name text[]) RETURNS +TABLE(TEST_NAME text, STATUS text, MESSAGE text, RUNTIME bigint, ENABLED text) +as 'babelfishpg_unit', 'babelfishpg_unit_run_tests' +LANGUAGE C IMMUTABLE STRICT; diff --git a/contrib/babelfishpg_unit/babelfishpg_unit.c b/contrib/babelfishpg_unit/babelfishpg_unit.c new file mode 100644 index 0000000000..6be1192628 --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit.c @@ -0,0 +1,351 @@ +#include "babelfishpg_unit.h" + +Datum babelfishpg_unit_run_tests(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(babelfishpg_unit_run_tests); + + +#define NCOLS (5) + +#define TEST_NAME_COLUMN 0 +#define STATUS_NAME_COLUMN (TEST_NAME_COLUMN + 1) +#define MESSAGE_NAME_COLUMN (STATUS_NAME_COLUMN + 1) +#define RUNTIME_NAME_COLUMN (MESSAGE_NAME_COLUMN + 1) +#define ENABLED_NAME_COLUMN (RUNTIME_NAME_COLUMN + 1) + +#define TEXT_HEADER_SIZE (28) + +typedef struct +{ + TestResult *(*test_func)(); + bool enabled; + char test_func_name[MAX_TEST_NAME_LENGTH]; + char category[MAX_TEST_NAME_LENGTH]; +} TestInfo; + +typedef struct +{ + bool nulls[NCOLS]; + TupleDesc tupledesc; + int test_run; + int current_test; + int num_tests; + + /* + * When running categories or a list of tests ensure we don't run any test + * more than once. Simply maintain an array of booleans that indicate + * a test has been already included in this test run to prevent duplicates. + * It has 1-1 mapping to the tests array just below. + */ + short *test_included; +} StateInfo; + + +static char* PASS = "pass"; +static char* FAIL = "fail"; +static char* NOT_RUN = "no run"; +static char* ENABLED = "enabled"; +static char* DISABLED = "disabled"; + + +/* + * Add test metadata here. + * + * . Add function declaration + * . Add row to tests array that identifies your test containing: + * . Pointer to test function (takes no params and returns a TestResult pointer + * . enabled flag, true to enable + * . Human readable test name + * . Human readable category, tests can then be run by category, name, or all + * + * . Update for test declarations are needed in babelfishpg_unit.h + * . New tests can be added in their own file or an existing file if applicable. If + * adding to a new file, update Makefile to reference the new source file. + */ + + +TestInfo tests[]= +{ + {&test_int4_fixeddecimal_ge, true, "GreaterThanOrEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_le, true, "LesserThanOrEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_ne, true, "NotEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_eq, true, "EqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_lt, true, "LesserThanCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_cmp, true, "Comparison_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_fixeddecimalum, true, "FIXEDDECIMALUM", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_ge, true, "GreaterThanOrEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_le, true, "LesserThanOrEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_gt, true, "GreaterThanCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_ne, true, "NotEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_cmp, true, "Comparison_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, +}; + + +// Forward declarations +TestResult *run_test(TestInfo *test); +void setNull(StateInfo *state, bool message); +void calc_num_tests(StateInfo *state); +void calc_tests_for_run(StateInfo *state, int arg_size, VarChar **args); +int calc_next_test(StateInfo *state, int position); + + +/* + * run_test + * + * Run a single test as specified by TestInfo. Return the result of + * running the test (TestResult) which contains pass/fail, runtime, and + * if supplied by the test a message concerning the test run. + * + */ +TestResult * +run_test(TestInfo *test) +{ + return test->test_func(); +} + + +/* + * setNull + * + * When returning a row or test run it is necessary to specify which columns + * are null. Only the message column can be null so if the message parameter + * is true, that column is set to be null + * + */ +void +setNull(StateInfo *state, bool message) +{ + int i; + + for (i=0; inulls[i] = false; + + if (message) + state->nulls[MESSAGE_NAME_COLUMN] = true; +} + + +/* + * calc_num_tests + * + * Calculate the total number of tests available to run, store + * it in the supplied state. + */ +void +calc_num_tests(StateInfo *state) +{ + state->num_tests = sizeof(tests) / sizeof(TestInfo); +} + + +/* + * calc_tests_for_run + * + * Given a list of test names or test categories scan the list + * of all tests and mark an array the same length as the list + * of all tests with those to run. + */ +void +calc_tests_for_run(StateInfo *state, int argc, text **argv) +{ + int i, j; + text **arg_ptr = argv; + + if (argc == 0) + { + memset(state->test_included, 1, state->num_tests * sizeof(short)); + return; + } + + + for (i=0; inum_tests; j++) + { + if ((strcmp(tests[j].test_func_name, testname) == 0) || + (strcmp(tests[j].category, testname) == 0)) { + state->test_included[j] = true; + } + } + pfree(testname); + } +} + + +/* + * calc_next_test + * + * Pass in the position in the test included array and start + * searching forward from position inclusive until end of array + * or until a test to run is found. If a test is found return + * that position, otherwise return the number of tests indicating + * we are beyond the range of tests and therefore there is no + * tests remaining to be run. + */ +int +calc_next_test(StateInfo *state, int position) +{ + if (position >= state->num_tests) + return state->num_tests; + + + while (state->test_included[position] == false) + { + if (position >= state->num_tests) + { + state->current_test = state->num_tests; + return state->num_tests; + } + + position++; + } + + return position; +} + + +Datum +babelfishpg_unit_run_tests(PG_FUNCTION_ARGS) +{ + FuncCallContext *fctx; + TupleDesc tupledesc; + Datum result; + Datum values[NCOLS]; + HeapTuple tuple; + MemoryContext mctx; + TestInfo *test; + TestResult *tr; + int nargs = PG_NARGS(); + text **args = NULL; + text **arg_ptr; + int i; + StateInfo* state; + ArrayType *arr; + Datum *decontructed_arr; + bool *nulls; + + if (SRF_IS_FIRSTCALL()) + { + + /* + * First call, allocate state needed for multiple + * calls to this routine. + */ + fctx = SRF_FIRSTCALL_INIT(); + mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); + state = palloc0(sizeof(StateInfo)); + + calc_num_tests(state); + + /* + * Based on input parameters calculate tests to + * run. Run all if no parameters provided, default + * case + */ + + if (nargs > 0) + { + /* + * Deconstructed the array for accessing the args passed to the function and + * Storing the content of parameters in 'args' + */ + arr = PG_GETARG_ARRAYTYPE_P(0); + deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, &decontructed_arr, &nulls, &nargs); + + args = palloc(nargs * sizeof(text *)); + for (i=0; itest_included = palloc0(state->num_tests * sizeof(short)); + calc_tests_for_run(state, nargs, args); + state->current_test = calc_next_test(state, 0); + if (args != NULL) + pfree(args); + + /* + * Create the tuple returned to the caller. Set up the + * table with the specified columns below. This only + * needs to be setup on the first call. + */ + tupledesc = CreateTemplateTupleDesc(NCOLS); + TupleDescInitEntry(tupledesc, (AttrNumber) TEST_NAME_COLUMN+1, "TEST_NAME", TEXTOID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) STATUS_NAME_COLUMN+1, "STATUS", TEXTOID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) MESSAGE_NAME_COLUMN+1, "MESSAGE", TEXTOID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) RUNTIME_NAME_COLUMN+1, "RUNTIME", INT8OID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) ENABLED_NAME_COLUMN+1, "ENABLED", TEXTOID, -1, 0); + + state->tupledesc = BlessTupleDesc(tupledesc); + fctx->user_fctx = state; + MemoryContextSwitchTo(mctx); + } + + /* + * Retrieve State Info needed to run the actual test + */ + fctx = SRF_PERCALL_SETUP(); + state = fctx->user_fctx; + tupledesc = state->tupledesc; + + if (state->current_test < state->num_tests) { + instr_time start, end; + test = &tests[state->current_test]; + setNull(state, false); + INSTR_TIME_SET_CURRENT(start); + + /* + * If enabled actually run the test + */ + if (test->enabled) + { + tr = run_test(test); + state->test_run++; + } else + { + tr = palloc0(sizeof(TestResult)); + } + + /* + * Compute timing information and if a message was returned and + * set message column to null if it is null message + */ + INSTR_TIME_SET_CURRENT(end); + + tr->run_time = INSTR_TIME_GET_MICROSEC(end) - INSTR_TIME_GET_MICROSEC(start); + if (tr->message == NULL) + setNull(state, true); + + /* + * Set the information for a row of data indicating test failure or pass + */ + values[TEST_NAME_COLUMN] = PointerGetDatum(cstring_to_text(test->test_func_name)); + values[STATUS_NAME_COLUMN] = PointerGetDatum(cstring_to_text(test->enabled ? + (tr->result ? PASS : FAIL) : NOT_RUN)); + values[MESSAGE_NAME_COLUMN] = PointerGetDatum(cstring_to_text(tr->message)); + values[RUNTIME_NAME_COLUMN] = PointerGetDatum(tr->run_time); + values[ENABLED_NAME_COLUMN] = PointerGetDatum(cstring_to_text(test->enabled ? ENABLED : DISABLED)); + tuple = heap_form_tuple(state->tupledesc, values, state->nulls); + result = HeapTupleGetDatum(tuple); + + /* + * Set the state to run the next test on the next function call + */ + state->current_test = calc_next_test(state, state->current_test + 1); + + pfree(tr); + + SRF_RETURN_NEXT(fctx, result); + } + + /* + * All the requested tests have been processed, do final return + */ + pfree(state->test_included); + pfree(state); + SRF_RETURN_DONE(fctx); +} diff --git a/contrib/babelfishpg_unit/babelfishpg_unit.control b/contrib/babelfishpg_unit/babelfishpg_unit.control new file mode 100644 index 0000000000..798ae1406f --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit.control @@ -0,0 +1,4 @@ +comment = 'Unit testing framework for babelfish' +default_version = '1.0.0' +module_pathname = '$libdir/babelfishpg_unit' +schema = 'babelfishpg_unit' diff --git a/contrib/babelfishpg_unit/babelfishpg_unit.h b/contrib/babelfishpg_unit/babelfishpg_unit.h new file mode 100644 index 0000000000..2bcf272fdb --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit.h @@ -0,0 +1,59 @@ +#include "postgres.h" +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/elog.h" +#include +#include "access/htup_details.h" +#include "access/clog.h" +#include "catalog/pg_type.h" +#include "funcapi.h" +#include "access/rmgr.h" +#include "access/xlog_internal.h" +#include "storage/backendid.h" +#include "storage/smgr.h" + +#include "utils/memutils.h" + +#define MAX_TEST_NAME_LENGTH (256) +#define MAX_TEST_MESSAGE_LENGTH (2048) + +typedef struct +{ + bool result; + char message[MAX_TEST_MESSAGE_LENGTH]; + char testcase_message[MAX_TEST_MESSAGE_LENGTH]; + uint64 run_time; +} TestResult; + + +#define TEST_ASSERT(condition, pResult) \ +do { \ + if(pResult->result == false){ \ + snprintf((pResult)->message, \ + MAX_TEST_MESSAGE_LENGTH, \ + "Test assertion '%s' failed at %s:%d", \ + #condition, __FILE__, __LINE__); \ + } \ +} while (0) + + +#define TEST_ASSERT_TESTCASE(condition, pResult) \ +do { \ + if (!(condition)) { \ + (pResult)->result = false; \ + } \ +} while (0) + + +extern TestResult *test_int4_fixeddecimal_ge(void); +extern TestResult *test_int4_fixeddecimal_le(void); +extern TestResult *test_int4_fixeddecimal_ne(void); +extern TestResult *test_int4_fixeddecimal_eq(void); +extern TestResult *test_int4_fixeddecimal_lt(void); +extern TestResult *test_int4_fixeddecimal_cmp(void); +extern TestResult *test_fixeddecimalum(void); +extern TestResult *test_fixeddecimal_int2_ge(void); +extern TestResult *test_fixeddecimal_int2_le(void); +extern TestResult *test_fixeddecimal_int2_gt(void); +extern TestResult *test_fixeddecimal_int2_ne(void); +extern TestResult *test_fixeddecimal_int2_cmp(void); diff --git a/contrib/babelfishpg_unit/test_money.c b/contrib/babelfishpg_unit/test_money.c new file mode 100644 index 0000000000..daaebfbc33 --- /dev/null +++ b/contrib/babelfishpg_unit/test_money.c @@ -0,0 +1,413 @@ +#include "babelfishpg_unit.h" +#include "../babelfishpg_money/fixeddecimal.c" + +/* + * These are the test functions which returns a TestResult structure containing the result of the test. + * We will expect some result and the obtained result is compared with the expected result using the TEST_ASSERT and TEST_ASSERT_TESTCASE macro. + * If the obtained result matches the expected result, the test passes; otherwise, it fails. + */ + +TestResult* +test_int4_fixeddecimal_ge(void) +{ + /* + * This function checks whether val1 is greater than or equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] >= val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_le(void) +{ + /* + * This function checks whether val1 is lesser than or equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] <= val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_le, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_ne(void) +{ + /* + * This function checks whether val1 is not equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] != val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_ne, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_eq(void) +{ + /* + * This function checks whether val1 is equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] == val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_eq, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_lt(void) +{ + /* + * This function checks whether val1 is less than val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] < val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_lt, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_cmp(void) +{ + /* + * This function compares val1 and val2. + * val1 > val2 then result will be 1 + * val1 == val2 then result will be 0 + * val1 < val2 then result will be -1 + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + Datum val1_datum = Int32GetDatum(val1[i]); + Datum val2_datum = Int32GetDatum(val2[i]); + + Datum expected; + Datum obtained; + char expected_str[MAX_TEST_MESSAGE_LENGTH]; + char obtained_str[MAX_TEST_MESSAGE_LENGTH]; + + if(val1[i] > val2[i]) + expected = 1; + else if(val1[i] < val2[i]) + expected = -1; + else + expected = 0; + + obtained = DirectFunctionCall2(int4_fixeddecimal_cmp, val1_datum, val2_datum); + snprintf(expected_str, MAX_TEST_MESSAGE_LENGTH, "%ld", expected); + snprintf(obtained_str, MAX_TEST_MESSAGE_LENGTH, "%ld", obtained); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimalum(void) +{ + /* + * To establish the expected behavior of our code, it is crucial to test both positive and negative scenarios. + * So in this test, we expect an out of range error. + * When this error occurs as anticipated, the test is considered successful. + */ + + int64 arg1 = INT64_MIN; + ErrorData *errorData; + MemoryContext oldcontext; + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = false; + + oldcontext = CurrentMemoryContext; + PG_TRY(); + { + DirectFunctionCall1(fixeddecimalum, arg1); + } + PG_CATCH(); + { + MemoryContextSwitchTo(oldcontext); + errorData = CopyErrorData(); + FlushErrorState(); + snprintf(testResult->message, MAX_TEST_MESSAGE_LENGTH, "%s", errorData->message); + testResult->result = true; + FreeErrorData(errorData); + } + PG_END_TRY(); + + // If the error doesn't occurr, then the following message gets displayed + if(testResult->result == false) + strncpy(testResult->message, ", Out of Range error doesn't occur", MAX_TEST_MESSAGE_LENGTH); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_ge(void) +{ + /* + * This function checks whether val1 is greater than or equal to val2 or not. + */ + + int val1[] = {152, -100, 5, 0, -85, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] >= val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_le(void) +{ + /* + * This function checks whether val1 is less than or equal to val2 or not. + */ + + int val1[] = {152, -100, 5, 0, -85, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] <= val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_le, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_gt(void) +{ + /* + * This function checks whether val1 is greater than val2 or not. + */ + + int val1[] = {152, -100, 5, 0, -85}; + int val2[] = {982, 200, 0, -24, -567}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] > val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_ne(void) +{ + /* + * This function checks whether val1 is not equal to val2 or not. + */ + + int val1[] = {5, 0, -85}; + int val2[] = {0, -24, -567}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + bool expected = (val1[i] != val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_cmp(void) +{ + /* + * This function compares val1 and val2. + * val1 > val2 then result will be 1 + * val1 == val2 then result will be 0 + * val1 < val2 then result will be -1 + */ + + int val1[] = {152, -100, 5, 0, -85, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) + { + Datum val1_datum = Int32GetDatum(val1[i]); + Datum val2_datum = Int32GetDatum(val2[i]); + + Datum expected; + Datum obtained; + char expected_str[MAX_TEST_MESSAGE_LENGTH]; + char obtained_str[MAX_TEST_MESSAGE_LENGTH]; + + if(val1[i] > val2[i]) + expected = 1; + else if(val1[i] < val2[i]) + expected = -1; + else + expected = 0; + + obtained = DirectFunctionCall2(fixeddecimal_int2_cmp, val1_datum, val2_datum); + snprintf(expected_str, MAX_TEST_MESSAGE_LENGTH, "%ld", expected); + snprintf(obtained_str, MAX_TEST_MESSAGE_LENGTH, "%ld", obtained); + + TEST_ASSERT_TESTCASE(expected == obtained, testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} diff --git a/dev-tools.sh b/dev-tools.sh index e351a5b455..dd23a63940 100755 --- a/dev-tools.sh +++ b/dev-tools.sh @@ -32,20 +32,37 @@ 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" 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" + 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" + echo "" + echo " run_pgindent [TARGET_WS]" + echo " run pgindent" exit 0 fi @@ -60,9 +77,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 @@ -125,7 +165,7 @@ init_db() { bin/pg_ctl -D data/ -l logfile start cd data sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/g" postgresql.conf - sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds'/g" postgresql.conf + sudo sed -i "s/#shared_preload_libraries = ''/shared_preload_libraries = 'babelfishpg_tds, pg_stat_statements'/g" postgresql.conf sudo echo "host all all 0.0.0.0/0 trust" >> pg_hba.conf restart $1 } @@ -133,7 +173,7 @@ init_db() { init_pghint() { cd $1 if [ ! -d "./pg_hint_plan" ]; then - git clone --depth 1 --branch REL14_1_4_0 https://github.com/ossc-db/pg_hint_plan.git + git clone --depth 1 --branch REL15_1_5_1 https://github.com/ossc-db/pg_hint_plan.git fi cd pg_hint_plan export PATH=$2/postgres/bin:$PATH @@ -155,8 +195,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 --roles-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 --roles-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 } @@ -170,12 +216,129 @@ 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 +} + +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 + 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 @@ -211,8 +374,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 +396,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..." @@ -270,14 +457,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 @@ -293,4 +480,17 @@ 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 +elif [ "$1" == "build_coverage" ]; then + build_coverage $TARGET_WS + exit 0 +elif [ "$1" == "sum_coverage" ]; then + sum_coverage $TARGET_WS + exit 0 fi diff --git a/test/JDBC/README.md b/test/JDBC/README.md index 6c793d5944..69ef41f32b 100644 --- a/test/JDBC/README.md +++ b/test/JDBC/README.md @@ -18,6 +18,7 @@ The JDBC test framework for Babelfish uses the JDBC Driver for SQL Server for da - [IMPORTANT](#important) - [Adding the test cases](#adding-the-test-cases) - [Reading the console output and diff](#reading-the-console-output-and-diff) +- [Running Tests with Parallel Query Enabled](#running-tests-with-parallel-query-enabled) ## Running the test framework @@ -382,3 +383,35 @@ You will also be provided with the location of the `.diff` file containing the d - `mm` → minutes - `ss` → seconds - `SSS` → milliseconds + + +## Running Tests with Parallel Query Enabled + +After building the modified PostgreSQL engine and Babelfish extensions using the [online instructions](../../contrib/README.md), you must: +1. Create a PostgreSQL database and initialize Babelfish (if you already have a database with Babelfish initialized, you can omit this step or perform the cleanup steps before you initialize) to enable parallel query mode pass -enable_parallel_query flag when running ./init.sh + + ```bash + ./init.sh -enable_parallel_query + ``` +3. Before running JDBC tests, please take note that currently not all JDBC tests runs sucessfully with parallel query mode on. Certain JDBC tests are encountering issues, such as crashes, failures, or timeouts when executed with parallel query mode enabled. So we need these problematic tests to be excluded from running via jdbc framework. File `parallel_query_jdbc_schedule` contains test-cases names with prefix `ignore#!#` that are problematic and needs to be avoided from being run. To exclude these problematic tests from running via the JDBC framework, use the `isParallelQueryMode` environment variable. You can set it to `true`: + + ```bash + export isParallelQueryMode=true + # Verify if isParallelQueryMode is set to true + echo $isParallelQueryMode + ``` +4. Now Run the tests: + ```bash + mvn test + ``` +5. If the expected output is different when run in parallel query mode and in normal mode, one can add a different expected output specially for parallel query mode in `expected/parallel_query/` folder. Additionally, one needs to add `-- parallel_query_expected` flag in the corresponding input file. +6. Cleanup all the objects, users, roles and databases created while running the tests: + ```bash + ./cleanup.sh + ``` +7. Please note that when you have completed testing with parallel query mode enabled, you should unset the `isParallelQueryMode` environment variable that was previously set to `true`. This ensures that all tests run in the normal Babelfish mode (without parallel query): + + ```bash + unset isParallelQueryMode + ``` +If you encounter failing or crashing tests in the "JDBC tests with parallel query" GitHub workflow, consider adding the names of these problematic test cases to the `parallel_query_jdbc_schedule` file. Prefix these test case names with `ignore#!#`. As we work towards resolving these issues in the future, we will gradually remove these excluded tests from the `parallel_query_jdbc_schedule` scheduling file. diff --git a/test/JDBC/expected/14_10__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/14_10__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/14_10__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_10__preparation__Test-sp_babelfish_volatility-vu-prepare.out b/test/JDBC/expected/14_10__preparation__Test-sp_babelfish_volatility-vu-prepare.out new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/expected/14_10__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_3__preparation__ISC-Columns-vu-prepare.out b/test/JDBC/expected/14_3__preparation__ISC-Columns-vu-prepare.out index 89c6051a5d..491ba440ec 100644 --- a/test/JDBC/expected/14_3__preparation__ISC-Columns-vu-prepare.out +++ b/test/JDBC/expected/14_3__preparation__ISC-Columns-vu-prepare.out @@ -10,6 +10,10 @@ GO CREATE TABLE isc_columns_vu_prepare_nums(a INT, b SMALLINT, c TINYINT, d BIGINT, e BIT, f FLOAT, g REAL, h NUMERIC(5,3), i MONEY, j SMALLMONEY) GO +-- test bytea datatype +CREATE TABLE isc_columns_vu_prepare_bytea(a bytea, b image) +GO + -- test with different db CREATE DATABASE isc_columns_db1 GO @@ -49,3 +53,8 @@ GO CREATE VIEW isc_columns_vu_prepare_v1 AS SELECT * FROM information_schema.columns WHERE TABLE_NAME LIKE '%isc_columns_UDT%' ORDER BY DATA_TYPE,COLUMN_NAME GO + +-- dep view +CREATE VIEW isc_columns_bytea_v2 AS + SELECT * FROM information_schema.columns WHERE TABLE_NAME = 'isc_columns_vu_prepare_bytea' ORDER BY DATA_TYPE,COLUMN_NAME +GO diff --git a/test/JDBC/expected/14_5__preparation__ISC-Columns-vu-prepare.out b/test/JDBC/expected/14_5__preparation__ISC-Columns-vu-prepare.out index 89c6051a5d..491ba440ec 100644 --- a/test/JDBC/expected/14_5__preparation__ISC-Columns-vu-prepare.out +++ b/test/JDBC/expected/14_5__preparation__ISC-Columns-vu-prepare.out @@ -10,6 +10,10 @@ GO CREATE TABLE isc_columns_vu_prepare_nums(a INT, b SMALLINT, c TINYINT, d BIGINT, e BIT, f FLOAT, g REAL, h NUMERIC(5,3), i MONEY, j SMALLMONEY) GO +-- test bytea datatype +CREATE TABLE isc_columns_vu_prepare_bytea(a bytea, b image) +GO + -- test with different db CREATE DATABASE isc_columns_db1 GO @@ -49,3 +53,8 @@ GO CREATE VIEW isc_columns_vu_prepare_v1 AS SELECT * FROM information_schema.columns WHERE TABLE_NAME LIKE '%isc_columns_UDT%' ORDER BY DATA_TYPE,COLUMN_NAME GO + +-- dep view +CREATE VIEW isc_columns_bytea_v2 AS + SELECT * FROM information_schema.columns WHERE TABLE_NAME = 'isc_columns_vu_prepare_bytea' ORDER BY DATA_TYPE,COLUMN_NAME +GO 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_6__preparation__Test_ISNULL-vu-prepare.out b/test/JDBC/expected/14_6__preparation__Test_ISNULL-vu-prepare.out new file mode 100644 index 0000000000..a8db7dea24 --- /dev/null +++ b/test/JDBC/expected/14_6__preparation__Test_ISNULL-vu-prepare.out @@ -0,0 +1,76 @@ +CREATE TABLE [dbo].[test_isnull_table]( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [my_varchar_data] [varchar](20) NULL, + [my_computed_column] AS isnull([my_varchar_data],[id])) +GO + +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES ('1') +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES (NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view [dbo].[test_isnull_view] as select isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view1] as select * from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO + +create view [dbo].[test_isnull_view2] as select * from [dbo].[test_isnull_table] where isnull(NULL,[id]) = 1; +GO + +create view [dbo].[test_isnull_view3] as +select ISNULL(NULL, NULL); +GO + +create view [dbo].[test_isnull_view4] as +select ISNULL(NULL, 'Unassigned'); +GO + +create view [dbo].[test_isnull_view5] as +select + ISNULL([my_varchar_data], 'Unassigned') +from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view6] as +select ISNULL('Unassigned', 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "Unassigned")~~ + + +create view [dbo].[test_isnull_view7] as +select ISNULL ('', 5); +GO + +CREATE FUNCTION [dbo].[test_isnull_func1]() +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT + SELECT @ans= isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1 + RETURN @ans +END +GO + +CREATE FUNCTION [dbo].[test_isnull_func2](@in1 varchar(20), @in2 bigint) +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT = isnull(@in1, @in2) + RETURN @ans +END +GO + +CREATE PROCEDURE [dbo].[test_isnull_proc1] +AS +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +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/14_9__preparation__BABEL-2877-vu-prepare.out b/test/JDBC/expected/14_9__preparation__BABEL-2877-vu-prepare.out new file mode 100644 index 0000000000..aa91e6afde --- /dev/null +++ b/test/JDBC/expected/14_9__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_9__preparation__Test-sp_babelfish_volatility-vu-prepare.out b/test/JDBC/expected/14_9__preparation__Test-sp_babelfish_volatility-vu-prepare.out new file mode 100644 index 0000000000..9be5872d7d --- /dev/null +++ b/test/JDBC/expected/14_9__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_9__preparation__Test_ISNULL-vu-prepare.out b/test/JDBC/expected/14_9__preparation__Test_ISNULL-vu-prepare.out new file mode 100644 index 0000000000..a8db7dea24 --- /dev/null +++ b/test/JDBC/expected/14_9__preparation__Test_ISNULL-vu-prepare.out @@ -0,0 +1,76 @@ +CREATE TABLE [dbo].[test_isnull_table]( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [my_varchar_data] [varchar](20) NULL, + [my_computed_column] AS isnull([my_varchar_data],[id])) +GO + +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES ('1') +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES (NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view [dbo].[test_isnull_view] as select isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view1] as select * from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO + +create view [dbo].[test_isnull_view2] as select * from [dbo].[test_isnull_table] where isnull(NULL,[id]) = 1; +GO + +create view [dbo].[test_isnull_view3] as +select ISNULL(NULL, NULL); +GO + +create view [dbo].[test_isnull_view4] as +select ISNULL(NULL, 'Unassigned'); +GO + +create view [dbo].[test_isnull_view5] as +select + ISNULL([my_varchar_data], 'Unassigned') +from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view6] as +select ISNULL('Unassigned', 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "Unassigned")~~ + + +create view [dbo].[test_isnull_view7] as +select ISNULL ('', 5); +GO + +CREATE FUNCTION [dbo].[test_isnull_func1]() +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT + SELECT @ans= isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1 + RETURN @ans +END +GO + +CREATE FUNCTION [dbo].[test_isnull_func2](@in1 varchar(20), @in2 bigint) +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT = isnull(@in1, @in2) + RETURN @ans +END +GO + +CREATE PROCEDURE [dbo].[test_isnull_proc1] +AS +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO diff --git a/test/JDBC/expected/15003_1.out b/test/JDBC/expected/15003_1.out new file mode 100644 index 0000000000..bcf2aebe25 --- /dev/null +++ b/test/JDBC/expected/15003_1.out @@ -0,0 +1,320 @@ +USE master +GO + +-- simple batch +-- pre setup +create schema error_mapping; +GO + +CREATE LOGIN login_15003 WITH PASSWORD = '123456789' +GO + +CREATE USER user_15003 FOR LOGIN login_15003 WITH DEFAULT_SCHEMA = error_mapping +GO + +-- psql +GRANT ALL ON SCHEMA master_error_mapping TO master_user_15003; +GO + +-- tsql user=login_15003 password=123456789 +-- error stmt +EXEC sp_enum_oledb_providers +GO +~~ERROR (Code: 15003)~~ + +~~ERROR (Message: Only members of the sysadmin role can execute this stored procedure.)~~ + + + +-- post setup +-- to check if error is being raised during parse analysis phase +create table error_mapping.temp1 (a int) +GO + + +-- pre setup +create procedure error_mapping.ErrorHandling1 as +begin +insert into error_mapping.temp1 values(1) +EXEC sp_enum_oledb_providers +end +GO + + +-- post setup +create table error_mapping.temp2 (a int) +GO + + +-- pre setup +insert into error_mapping.temp2 values(1) +EXEC sp_enum_oledb_providers +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 15003)~~ + +~~ERROR (Message: Only members of the sysadmin role can execute this stored procedure.)~~ + + + + +-- post setup +-- Here we are assuming that error_mapping.ErrorHandling1 is created with no error +create table error_mapping.temp3 (a int) +GO + +-- pre setup +insert into error_mapping.temp3 values(1) +exec error_mapping.ErrorHandling1; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 15003)~~ + +~~ERROR (Message: Only members of the sysadmin role can execute this stored procedure.)~~ + + + +-- post setup +if ((select count(*) from error_mapping.temp1) = 0 and (select count(*) from error_mapping.temp2) = 0 and (select count(*) from error_mapping.temp3) > 0) select cast('parse analysis phase error' as text) +GO + +drop procedure error_mapping.ErrorHandling1; +GO + +drop table error_mapping.temp1; +drop table error_mapping.temp2; +drop table error_mapping.temp3; +GO + + + +-- compile time error portion +-- pre setup +create procedure error_mapping.ErrorHandling1 as +begin +EXEC sp_enum_oledb_providers +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +if @@error > 0 select cast('Compile time error' as text); +if @@trancount > 0 rollback transaction; +drop procedure error_mapping.ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO + + + + +-- post setup +-- checking if compile time error rollback the transaction +-- pre setup +begin transaction +GO + +create procedure error_mapping.ErrorHandling1 as +begin +EXEC sp_enum_oledb_providers +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO + +declare @err int = @@error; if (@err > 0 and @@trancount > 0) select cast('BATCH ONLY TERMINATING' as text) else if @err > 0 select cast('BATCH TERMINATING\ txn rolledback' as text); +if @@trancount > 0 rollback transaction; +drop procedure error_mapping.ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "master_error_mapping.errorhandling1")~~ + + + + +-- post setup +-- Checking xact_abort_flag for compile time error +set xact_abort ON; +GO + + +-- pre setup +begin transaction +GO + +create procedure error_mapping.ErrorHandling1 as +begin +EXEC sp_enum_oledb_providers +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +end +GO + +declare @err int = @@error; if (@err > 0 and @@trancount > 0) select cast('BATCH ONLY TERMINATING' as text) else if @err > 0 select cast('BATCH TERMINATING\ txn rolledback' as text); +if @@trancount > 0 rollback transaction; +drop procedure error_mapping.ErrorHandling1; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "master_error_mapping.errorhandling1")~~ + + + + +-- post setup +-- Next portion is for runtime error +create procedure error_mapping.ErrorHandling1 as +begin +EXEC sp_enum_oledb_providers +if @@error > 0 select cast('STATEMENT TERMINATING ERROR' as text); +select @@trancount; +end +GO + +create procedure error_mapping.ErrorHandling2 as +begin +exec error_mapping.ErrorHandling1; +if @@error > 0 select cast('CURRENT BATCH TERMINATING ERROR' as text); +end +GO + +begin transaction; +GO +exec error_mapping.ErrorHandling2; +GO +~~ERROR (Code: 15003)~~ + +~~ERROR (Message: Only members of the sysadmin role can execute this stored procedure.)~~ + +~~START~~ +text +STATEMENT TERMINATING ERROR +~~END~~ + +~~START~~ +int +1 +~~END~~ + +declare @err int = @@error; if (@err > 0 and @@trancount > 0) select cast('BATCH ONLY TERMINATING' as text) else if @err > 0 select cast('BATCH TERMINATING\ txn rolledback' as text); +if @@trancount > 0 rollback transaction; +drop procedure error_mapping.ErrorHandling1; +drop procedure error_mapping.ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + + +-- checking xact_abort flag for runtime error +set xact_abort ON; +GO + +create procedure error_mapping.ErrorHandling1 as +begin +EXEC sp_enum_oledb_providers +if @@error > 0 select cast('Does not respect the xact_abort flag' as text); +select @@trancount; +end +GO + +create procedure error_mapping.ErrorHandling2 as +begin +exec error_mapping.ErrorHandling1; +if @@error > 0 select cast('Does not respect the xact_abort flag' as text); +end +GO + +begin transaction; +GO +exec error_mapping.ErrorHandling2; +GO +~~ERROR (Code: 15003)~~ + +~~ERROR (Message: Only members of the sysadmin role can execute this stored procedure.)~~ + +~~START~~ +text +Does not respect the xact_abort flag +~~END~~ + +~~START~~ +int +1 +~~END~~ + +declare @err int = @@error; if (@err > 0 and @@trancount > 0) select cast('does not respect xact_abort flag' as text) else if @err > 0 select cast('respects xact_abort flag' as text); +if @@trancount > 0 rollback transaction; +drop procedure error_mapping.ErrorHandling1; +drop procedure error_mapping.ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO + + + +-- try catch +-- pre setup +create table error_mapping.temp1 (a int) +GO + +begin try +insert into error_mapping.temp1 values (1); +EXEC sp_enum_oledb_providers +end try +begin catch + select xact_state(); + select * from error_mapping.temp1; +end catch +if @@trancount > 0 rollback transaction; +drop procedure error_mapping.ErrorHandling1; +drop procedure error_mapping.ErrorHandling2; +set xact_abort OFF; +set implicit_transactions OFF; +GO +~~ROW COUNT: 1~~ + +~~START~~ +smallint +0 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "master_error_mapping.errorhandling1")~~ + +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "master_error_mapping.errorhandling2")~~ + + +drop table error_mapping.temp1 +GO + +-- terminate-tsql-conn user=login_15003 password=123456789 + +-- psql +-- post setup +REVOKE ALL ON SCHEMA master_error_mapping FROM master_user_15003; +GO + +-- tsql +DROP LOGIN login_15003 +GO + +DROP USER user_15003 +GO + +DROP SCHEMA error_mapping +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/15_2__preparation__Test_ISNULL-vu-prepare.out b/test/JDBC/expected/15_2__preparation__Test_ISNULL-vu-prepare.out new file mode 100644 index 0000000000..a8db7dea24 --- /dev/null +++ b/test/JDBC/expected/15_2__preparation__Test_ISNULL-vu-prepare.out @@ -0,0 +1,76 @@ +CREATE TABLE [dbo].[test_isnull_table]( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [my_varchar_data] [varchar](20) NULL, + [my_computed_column] AS isnull([my_varchar_data],[id])) +GO + +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES ('1') +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES (NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view [dbo].[test_isnull_view] as select isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view1] as select * from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO + +create view [dbo].[test_isnull_view2] as select * from [dbo].[test_isnull_table] where isnull(NULL,[id]) = 1; +GO + +create view [dbo].[test_isnull_view3] as +select ISNULL(NULL, NULL); +GO + +create view [dbo].[test_isnull_view4] as +select ISNULL(NULL, 'Unassigned'); +GO + +create view [dbo].[test_isnull_view5] as +select + ISNULL([my_varchar_data], 'Unassigned') +from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view6] as +select ISNULL('Unassigned', 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "Unassigned")~~ + + +create view [dbo].[test_isnull_view7] as +select ISNULL ('', 5); +GO + +CREATE FUNCTION [dbo].[test_isnull_func1]() +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT + SELECT @ans= isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1 + RETURN @ans +END +GO + +CREATE FUNCTION [dbo].[test_isnull_func2](@in1 varchar(20), @in2 bigint) +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT = isnull(@in1, @in2) + RETURN @ans +END +GO + +CREATE PROCEDURE [dbo].[test_isnull_proc1] +AS +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO diff --git a/test/JDBC/expected/15_4__preparation__Test_ISNULL-vu-prepare.out b/test/JDBC/expected/15_4__preparation__Test_ISNULL-vu-prepare.out new file mode 100644 index 0000000000..a8db7dea24 --- /dev/null +++ b/test/JDBC/expected/15_4__preparation__Test_ISNULL-vu-prepare.out @@ -0,0 +1,76 @@ +CREATE TABLE [dbo].[test_isnull_table]( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [my_varchar_data] [varchar](20) NULL, + [my_computed_column] AS isnull([my_varchar_data],[id])) +GO + +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES ('1') +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES (NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view [dbo].[test_isnull_view] as select isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view1] as select * from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO + +create view [dbo].[test_isnull_view2] as select * from [dbo].[test_isnull_table] where isnull(NULL,[id]) = 1; +GO + +create view [dbo].[test_isnull_view3] as +select ISNULL(NULL, NULL); +GO + +create view [dbo].[test_isnull_view4] as +select ISNULL(NULL, 'Unassigned'); +GO + +create view [dbo].[test_isnull_view5] as +select + ISNULL([my_varchar_data], 'Unassigned') +from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view6] as +select ISNULL('Unassigned', 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "Unassigned")~~ + + +create view [dbo].[test_isnull_view7] as +select ISNULL ('', 5); +GO + +CREATE FUNCTION [dbo].[test_isnull_func1]() +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT + SELECT @ans= isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1 + RETURN @ans +END +GO + +CREATE FUNCTION [dbo].[test_isnull_func2](@in1 varchar(20), @in2 bigint) +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT = isnull(@in1, @in2) + RETURN @ans +END +GO + +CREATE PROCEDURE [dbo].[test_isnull_proc1] +AS +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO diff --git a/test/JDBC/expected/ATTIMEZONE-dep-vu-cleanup.out b/test/JDBC/expected/ATTIMEZONE-dep-vu-cleanup.out new file mode 100644 index 0000000000..641ba4caea --- /dev/null +++ b/test/JDBC/expected/ATTIMEZONE-dep-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP VIEW ATTIMEZONE_dep_vu_prepare_v1 +GO + +DROP VIEW ATTIMEZONE_dep_vu_prepare_v2 +GO + +DROP PROCEDURE ATTIMEZONE_dep_vu_prepare_p1 +GO + +DROP PROCEDURE ATTIMEZONE_dep_vu_prepare_p2 +GO + +DROP FUNCTION ATTIMEZONE_dep_vu_prepare_f1() +GO + +DROP FUNCTION ATTIMEZONE_dep_vu_prepare_f2() +GO diff --git a/test/JDBC/expected/ATTIMEZONE-dep-vu-prepare.out b/test/JDBC/expected/ATTIMEZONE-dep-vu-prepare.out new file mode 100644 index 0000000000..af3b38837b --- /dev/null +++ b/test/JDBC/expected/ATTIMEZONE-dep-vu-prepare.out @@ -0,0 +1,25 @@ +CREATE VIEW ATTIMEZONE_dep_vu_prepare_v1 as (Select convert(datetime2,'2002-01-01 02:01:00.000 +00:00') AT TIME ZONE 'Central Europe Standard Time'); +GO + +CREATE VIEW ATTIMEZONE_dep_vu_prepare_v2 as (Select 'hdhdhdhdj' AT TIME ZONE 'Eastern Standard Time'); +GO + +CREATE PROCEDURE ATTIMEZONE_dep_vu_prepare_p1 as (Select convert(datetimeoffset,'9999-12-31 15:59:59.000 +00:00') AT TIME ZONE 'Central Europe Standard Time'); +GO + +CREATE PROCEDURE ATTIMEZONE_dep_vu_prepare_p2 as (Select '9999-12-31 15:59:59.000 +00:00' AT TIME ZONE 'Central Europe Standard Time'); +GO + +CREATE FUNCTION ATTIMEZONE_dep_vu_prepare_f1() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (Select convert(datetime2,'2002-01-01 02:01:00.000 +00:00') AT TIME ZONE 'eAstern stAnDard tIMe'); +END +GO + +CREATE FUNCTION ATTIMEZONE_dep_vu_prepare_f2() +RETURNS DATETIMEOFFSET as +begin +RETURN (Select '2002-01-01 02:01:00.000 +00:00' AT TIME ZONE 'eAstern stAnDard tIMe'); +END +GO diff --git a/test/JDBC/expected/ATTIMEZONE-dep-vu-verify.out b/test/JDBC/expected/ATTIMEZONE-dep-vu-verify.out new file mode 100644 index 0000000000..5586310de7 --- /dev/null +++ b/test/JDBC/expected/ATTIMEZONE-dep-vu-verify.out @@ -0,0 +1,46 @@ +SELECT * FROM ATTIMEZONE_dep_vu_prepare_v1 +GO +~~START~~ +datetimeoffset +2002-01-01 02:01:00.0000000 +01:00 +~~END~~ + + +SELECT * FROM ATTIMEZONE_dep_vu_prepare_v2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +EXEC ATTIMEZONE_dep_vu_prepare_p1 +GO +~~START~~ +datetimeoffset +9999-12-31 16:59:59.0000000 +01:00 +~~END~~ + + +EXEC ATTIMEZONE_dep_vu_prepare_p2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +SELECT ATTIMEZONE_dep_vu_prepare_f1() +GO +~~START~~ +datetimeoffset +2002-01-01 02:01:00.0000000 -05:00 +~~END~~ + + +SELECT ATTIMEZONE_dep_vu_prepare_f2() +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + diff --git a/test/JDBC/expected/ATTIMEZONE.out b/test/JDBC/expected/ATTIMEZONE.out new file mode 100644 index 0000000000..f7af24b68b --- /dev/null +++ b/test/JDBC/expected/ATTIMEZONE.out @@ -0,0 +1,1310 @@ +Select convert(datetimeoffset,'2022-10-29 20:01:00.000') AT TIME ZONE NULL +Go +~~START~~ +datetimeoffset + +~~END~~ + + +Select NULL AT TIME ZONE 'Eastern Standard Time' +Go +~~START~~ +datetimeoffset + +~~END~~ + + +Select convert(datetime,'2022-10-29 20:01:00.000') AT TIME ZONE NULL +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select convert(datetime,'2022-10-29 20:01:00.000') AT TIME ZONE 'NULL' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type or the parameter NULL provided to AT TIME ZONE clause is invalid.)~~ + + +Select NULL AT TIME ZONE NULL +Go +~~START~~ +datetimeoffset + +~~END~~ + + +Select NULL AT TIME ZONE 'NULL' +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select 'NULL' AT TIME ZONE NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +Select 'NULL' AT TIME ZONE 'NULL' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +Select convert(datetime,'2022-10-29 20:01:00.000') AT TIME ZONE 'Eastern Standard Time' AT TIME ZONE 'Central Standard Time' +Go +~~START~~ +datetimeoffset +2022-10-29 19:01:00.0000000 -05:00 +~~END~~ + + +Select '2022-10-29 20:01:00.000' AT TIME ZONE convert(datetime,'2022-10-29 20:01:00.000') +Go +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +Select convert(datetimeoffset,'2022-10-29 20:01:00.000') AT TIME ZONE 23 +Go +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type or the parameter 23 provided to AT TIME ZONE clause is invalid.)~~ + + +Select convert(datetimeoffset,'2022-10-29 20:01:00.000') AT TIME ZONE convert(int,23) +Go +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type or the parameter 23 provided to AT TIME ZONE clause is invalid.)~~ + + +Select '2022-10-29 20:01:00.000' AT TIME ZONE 'Eastern Standard Time' +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +Select convert(datetime2,'2002-01-01 02:01:00.000 +00:00') AT TIME ZONE 'eAstern stAnDard tIMe' +GO +~~START~~ +datetimeoffset +2002-01-01 02:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetimeoffset,'2022-10-29 20:01:00.0000000 -05:00') AT TIME ZONE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type or the parameter Eastern Standard Time provided to AT TIME ZONE clause is invalid.)~~ + + +Select convert(datetimeoffset,'2022-10-29 20:01:00.0000000 -05:00') AT TIME ZONE 'Eastern Standard Time ' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type or the parameter Eastern Standard Time provided to AT TIME ZONE clause is invalid.)~~ + + +Select convert(datetime2,'2002-01-01 02:01:00.000 +00:00') AT TIME ZONE 'dgycgwycgqd' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type or the parameter dgycgwycgqd provided to AT TIME ZONE clause is invalid.)~~ + + +DECLARE @lvDate DATETIME, @lvDateUTC DATETIME +SET @lvDate = '2021-01-01' +SET @lvDateUTC = @lvDate AT TIME ZONE 'US Eastern Standard Time' AT TIME ZONE 'UTC' +SELECT @lvDate, @lvDateUTC +GO +~~START~~ +datetime#!#datetime +2021-01-01 00:00:00.0#!#2021-01-01 05:00:00.0 +~~END~~ + + +Select convert(datetime2,'2002-01-01 02:01:00.000 +00:00') aT TiMe ZoNE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +2002-01-01 02:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetime2,'2002-01-01 02:01:00.000 +00:00') aT TiMe ZoNE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +2002-01-01 02:01:00.0000000 -05:00 +~~END~~ + + +DROP TABLE IF EXISTS test +Create table test( a datetime) +insert into test(a) values(cast('1999-02-16' as datetime)) +GO +~~ROW COUNT: 1~~ + +DECLARE @testzone nvarchar(128) = 'Central European Standard Time'; +Select a AT TIME ZONE @testzone from test +GO +~~START~~ +datetimeoffset +1999-02-16 00:00:00.0000000 +01:00 +~~END~~ + + +DROP TABLE IF EXISTS test +GO + +Select convert(smalldatetime,'2022-10-29 20:01:24.426') AT TIME ZONE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +2022-10-29 20:01:00.0000000 -04:00 +~~END~~ + + +Select convert(time,' 20:01:24.426') AT TIME ZONE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +Select convert(date,'2022-10-29') AT TIME ZONE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + +Select 123 AT TIME ZONE 'Eastern Standard Time' +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 1 of AT TIME ZONE function.)~~ + + + +--Test covering all timezones +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'afghanistan standard time' AS 'afghanistan standard time'; +GO +~~START~~ +datetimeoffset +2023-09-16 05:31:00.0000000 +04:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'alaskan standard time' AS 'alaskan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 17:01:00.0000000 -08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'aleutian standard time' AS 'aleutian standard time'; +GO +~~START~~ +datetimeoffset +2023-09-15 16:01:00.0000000 -09:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'altai standard time' AS 'altai standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 08:01:00.0000000 +07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'arab standard time' AS 'arab standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'arabian standard time' AS 'arabian standard time'; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'arabic standard time' AS 'arabic standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'argentina standard time' AS 'argentina standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'astrakhan standard time' AS 'astrakhan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'atlantic standard time' AS 'atlantic standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'aus central standard time' AS 'aus central standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 10:31:00.0000000 +09:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'aus central w. standard time' AS 'aus central w. standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:46:00.0000000 +08:45 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'aus eastern standard time' AS 'aus eastern standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 11:01:00.0000000 +10:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'azerbaijan standard time' AS 'azerbaijan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'azores standard time' AS 'azores standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 01:01:00.0000000 +00:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'bahia standard time' AS 'bahia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'bangladesh standard time' AS 'bangladesh standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 07:01:00.0000000 +06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'belarus standard time' AS 'belarus standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'bougainville standard time' AS 'bougainville standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 12:01:00.0000000 +11:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'canada central standard time' AS 'canada central standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 19:01:00.0000000 -06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'cape verde standard time' AS 'cape verde standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 00:01:00.0000000 -01:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'caucasus standard time' AS 'caucasus standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'cen. australia standard time' AS 'cen. australia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 10:31:00.0000000 +09:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central america standard time' AS 'central america standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 19:01:00.0000000 -06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central asia standard time' AS 'central asia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 07:01:00.0000000 +06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central europe standard time' AS 'central europe standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central european standard time' AS 'central european standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central pacific standard time' AS 'central pacific standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 12:01:00.0000000 +11:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central standard time' AS 'central standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 20:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'central standard time (mexico)' AS 'central standard time (mexico)' ; +GO +~~START~~ +datetimeoffset +2023-09-15 20:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'chatham islands standard time' AS 'chatham islands standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 13:46:00.0000000 +12:45 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'china standard time' AS 'china standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:01:00.0000000 +08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'Cuba standard time' AS 'Cuba standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'dateline standard time' AS 'dateline standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 13:01:00.0000000 -12:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'e. africa standard time' AS 'e. africa standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'e. australia standard time' AS 'e. australia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 11:01:00.0000000 +10:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'e. europe standard time' AS 'e. europe standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'e. south america standard time' AS 'e. south america standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'easter island standard time' AS 'easter island standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 20:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'eastern standard time' AS 'eastern standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'eastern standard time (mexico)' AS 'eastern standard time (mexico)' ; +GO +~~START~~ +datetimeoffset +2023-09-15 20:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'egypt standard time' AS 'egypt standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'ekaterinburg standard time' AS 'ekaterinburg standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 06:01:00.0000000 +05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'fiji standard time' AS 'fiji standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 13:01:00.0000000 +12:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'fle standard time' AS 'fle standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'georgian standard time' AS 'georgian standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'gmt standard time' AS 'gmt standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 02:01:00.0000000 +01:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'greenland standard time' AS 'greenland standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 23:01:00.0000000 -02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'greenwich standard time' AS 'greenwich standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 01:01:00.0000000 +00:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'gtb standard time' AS 'gtb standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'haiti standard time' AS 'haiti standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'hawaiian standard time' AS 'hawaiian standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 15:01:00.0000000 -10:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'india standard time' AS 'india standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 06:31:00.0000000 +05:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'iran standard time' AS 'iran standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:31:00.0000000 +04:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'israel standard time' AS 'israel standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'jordan standard time' AS 'jordan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'kaliningrad standard time' AS 'kaliningrad standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'kamchatka standard time' AS 'kamchatka standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 13:01:00.0000000 +12:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'korea standard time' AS 'korea standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 10:01:00.0000000 +09:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'libya standard time' AS 'libya standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'line islands standard time' AS 'line islands standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 15:01:00.0000000 +14:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'lord howe standard time' AS 'lord howe standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 11:31:00.0000000 +10:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'magadan standard time' AS 'magadan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 12:01:00.0000000 +11:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'magallanes standard time' AS 'magallanes standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'marquesas standard time' AS 'marquesas standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 15:31:00.0000000 -09:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'mauritius standard time' AS 'mauritius standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'mid-atlantic standard time' AS 'mid-atlantic standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 23:01:00.0000000 -02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'middle east standard time' AS 'middle east standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'montevideo standard time' AS 'montevideo standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'morocco standard time' AS 'morocco standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 02:01:00.0000000 +01:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'mountain standard time' AS 'mountain standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 19:01:00.0000000 -06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'mountain standard time (mexico)' AS 'mountain standard time (mexico)' ; +GO +~~START~~ +datetimeoffset +2023-09-15 19:01:00.0000000 -06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'myanmar standard time' AS 'myanmar standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 07:31:00.0000000 +06:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'n. central asia standard time' AS 'n. central asia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 08:01:00.0000000 +07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'namibia standard time' AS 'namibia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'nepal standard time' AS 'nepal standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 06:46:00.0000000 +05:45 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'new zealand standard time' AS 'new zealand standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 13:01:00.0000000 +12:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'newfoundland standard time' AS 'newfoundland standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:31:00.0000000 -02:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'norfolk standard time' AS 'norfolk standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 12:01:00.0000000 +11:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'north asia east standard time' AS 'north asia east standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:01:00.0000000 +08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'north asia standard time' AS 'north asia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 08:01:00.0000000 +07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'omsk standard time' AS 'omsk standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 07:01:00.0000000 +06:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'pacific sa standard time' AS 'pacific sa standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'pacific standard time' AS 'pacific standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 18:01:00.0000000 -07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'pacific standard time (mexico)' AS 'pacific standard time (mexico)' ; +GO +~~START~~ +datetimeoffset +2023-09-15 18:01:00.0000000 -07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'paraguay standard time' AS 'paraguay standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'qyzylorda standard time' AS 'qyzylorda standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 06:01:00.0000000 +05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'romance standard time' AS 'romance standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'russia time zone 3' AS 'russia time zone 3' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'russia time zone 11' AS 'russia time zone 11' ; +GO +~~START~~ +datetimeoffset +2023-09-16 13:01:00.0000000 +12:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'Russian standard time' AS 'Russian standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'sa eastern standard time' AS 'sa eastern standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'sa pacific standard time' AS 'sa pacific standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 20:01:00.0000000 -05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'sa western standard time' AS 'sa western standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'saint pierre standard time' AS 'saint pierre standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 23:01:00.0000000 -02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'samoa standard time' AS 'samoa standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 14:01:00.0000000 +13:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'sao tome standard time' AS 'sao tome standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 01:01:00.0000000 +00:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'saratov standard time' AS 'saratov standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 05:01:00.0000000 +04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'se asia standard time' AS 'se asia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 08:01:00.0000000 +07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'singapore standard time' AS 'singapore standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:01:00.0000000 +08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'south africa standard time' AS 'south africa standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'south sudan standard time' AS 'south sudan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'sri Lanka standard time' AS 'sri Lanka standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 06:31:00.0000000 +05:30 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'sudan standard time' AS 'sudan standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'syria standard time' AS 'syria standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'taipei standard time' AS 'taipei standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:01:00.0000000 +08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'tasmania standard time' AS 'tasmania standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 11:01:00.0000000 +10:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'tocantins standard time' AS 'tocantins standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 22:01:00.0000000 -03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'tokyo standard time' AS 'tokyo standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 10:01:00.0000000 +09:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'tomsk standard time' AS 'tomsk standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 08:01:00.0000000 +07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'tonga standard time' AS 'tonga standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 14:01:00.0000000 +13:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'transbaikal standard time' AS 'transbaikal standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 10:01:00.0000000 +09:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'turkey standard time' AS 'turkey standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'turks and caicos standard time' AS 'turks and caicos standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'ulaanbaatar standard time' AS 'ulaanbaatar standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:01:00.0000000 +08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'us eastern standard time' AS 'us eastern standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'us mountain standard time' AS 'us mountain standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 18:01:00.0000000 -07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc' AS 'utc' ; +GO +~~START~~ +datetimeoffset +2023-09-16 01:01:00.0000000 +00:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc+12' AS 'utc+12' ; +GO +~~START~~ +datetimeoffset +2023-09-16 13:01:00.0000000 +12:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc+13' AS 'utc+13' ; +GO +~~START~~ +datetimeoffset +2023-09-16 14:01:00.0000000 +13:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc-02' AS 'utc-02' ; +GO +~~START~~ +datetimeoffset +2023-09-15 23:01:00.0000000 -02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc-08' AS 'utc-08' ; +GO +~~START~~ +datetimeoffset +2023-09-15 17:01:00.0000000 -08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc-09' AS 'utc-09' ; +GO +~~START~~ +datetimeoffset +2023-09-15 16:01:00.0000000 -09:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'utc-11' AS 'utc-11' ; +GO +~~START~~ +datetimeoffset +2023-09-15 14:01:00.0000000 -11:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'venezuela standard time' AS 'venezuela standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 21:01:00.0000000 -04:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'vladivostok standard time' AS 'vladivostok standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 11:01:00.0000000 +10:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'volgograd standard time' AS 'volgograd standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'w. australia standard time' AS 'w. australia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 09:01:00.0000000 +08:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'w. central africa standard time' AS 'w. central africa standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 02:01:00.0000000 +01:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'w. europe standard time' AS 'w. europe standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 03:01:00.0000000 +02:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'w. mongolia standard time' AS 'w. mongolia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 08:01:00.0000000 +07:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'west asia standard time' AS 'west asia standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 06:01:00.0000000 +05:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'west bank standard time' AS 'west bank standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 04:01:00.0000000 +03:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'west pacific standard time' AS 'west pacific standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 11:01:00.0000000 +10:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'yakutsk standard time' AS 'yakutsk standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-16 10:01:00.0000000 +09:00 +~~END~~ + + +Select convert(datetimeoffset,'2023-09-15 20:01:00.0000000 -05:00') AT TIME ZONE 'yukon standard time' AS 'yukon standard time' ; +GO +~~START~~ +datetimeoffset +2023-09-15 18:01:00.0000000 -07:00 +~~END~~ + + diff --git a/test/JDBC/expected/AUTO_ANALYZE-before-15-5-or-14-10-vu-prepare.out b/test/JDBC/expected/AUTO_ANALYZE-before-15-5-or-14-10-vu-prepare.out new file mode 100644 index 0000000000..c4361a6bd8 --- /dev/null +++ b/test/JDBC/expected/AUTO_ANALYZE-before-15-5-or-14-10-vu-prepare.out @@ -0,0 +1,9 @@ + +-- list all the babel catalogs that has been analyzed manually during extension create +-- will return NULL in this case +SELECT relname FROM pg_stat_all_tables WHERE schemaname = 'sys' and last_analyze IS NOT NULL order by relname +Go +~~START~~ +varchar +~~END~~ + diff --git a/test/JDBC/expected/AUTO_ANALYZE-before-15-5-or-14-10-vu-verify.out b/test/JDBC/expected/AUTO_ANALYZE-before-15-5-or-14-10-vu-verify.out new file mode 100644 index 0000000000..35f5cfa77e --- /dev/null +++ b/test/JDBC/expected/AUTO_ANALYZE-before-15-5-or-14-10-vu-verify.out @@ -0,0 +1,9 @@ + +-- list all the babel catalogs that has not been analyzed manually during extension upgrade +-- will return NULL in this case +SELECT relname FROM pg_stat_all_tables WHERE schemaname = 'sys' and last_analyze IS NULL order by relname +GO +~~START~~ +varchar +~~END~~ + diff --git a/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out b/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out new file mode 100644 index 0000000000..d569a9922d --- /dev/null +++ b/test/JDBC/expected/AUTO_ANALYZE-vu-prepare.out @@ -0,0 +1,34 @@ + +-- list all the babel catalogs that has not been analyzed manually during extension create +-- will return NULL in this case +SELECT relname FROM pg_stat_all_tables WHERE schemaname = 'sys' and last_analyze IS NULL order by relname +Go +~~START~~ +varchar +~~END~~ + + +-- list all the babel catalogs that has been analyzed manually during extension create +SELECT relname FROM pg_stat_all_tables WHERE schemaname = 'sys' and last_analyze IS NOT NULL order by relname +Go +~~START~~ +varchar +assemblies +babelfish_authid_login_ext +babelfish_authid_user_ext +babelfish_configurations +babelfish_domain_mapping +babelfish_extended_properties +babelfish_function_ext +babelfish_helpcollation +babelfish_namespace_ext +babelfish_schema_permissions +babelfish_server_options +babelfish_sysdatabases +babelfish_syslanguages +babelfish_view_def +service_settings +spt_datatype_info_table +versions +~~END~~ + diff --git a/test/JDBC/expected/AUTO_ANALYZE-vu-verify.out b/test/JDBC/expected/AUTO_ANALYZE-vu-verify.out new file mode 100644 index 0000000000..35f5cfa77e --- /dev/null +++ b/test/JDBC/expected/AUTO_ANALYZE-vu-verify.out @@ -0,0 +1,9 @@ + +-- list all the babel catalogs that has not been analyzed manually during extension upgrade +-- will return NULL in this case +SELECT relname FROM pg_stat_all_tables WHERE schemaname = 'sys' and last_analyze IS NULL order by relname +GO +~~START~~ +varchar +~~END~~ + diff --git a/test/JDBC/expected/BABEL-1206-vu-prepare.out b/test/JDBC/expected/BABEL-1206-vu-prepare.out index 10fc3f3ef6..35e0c938a7 100644 --- a/test/JDBC/expected/BABEL-1206-vu-prepare.out +++ b/test/JDBC/expected/BABEL-1206-vu-prepare.out @@ -17,7 +17,7 @@ CREATE NONCLUSTERED INDEX babel_1206_vu_prepare_t2_i1 ON babel_1206_vu_prepare_t2 ([Login] ASC, [UserLicenseKey] ASC, [PasswordSHA1] ASC) WITH (FILLFACTOR = 90); go -insert into babel_1206_vu_prepare_t2 values (0xaaa, 0xbbb, 1); +insert into babel_1206_vu_prepare_t2 values ('abc', 0xbbb, 1); go ~~ROW COUNT: 1~~ @@ -50,12 +50,12 @@ CREATE TABLE babel_1206_vu_prepare_t4( ) ON [PRIMARY] go -insert into babel_1206_vu_prepare_t4 values (0xaaa); +insert into babel_1206_vu_prepare_t4 values ('abc'); go ~~ROW COUNT: 1~~ --should throw an error because of duplicate index key -insert into babel_1206_vu_prepare_t4 values (0xaaa); +insert into babel_1206_vu_prepare_t4 values ('abc'); go ~~ERROR (Code: 2627)~~ diff --git a/test/JDBC/expected/BABEL-1309-vu-verify.out b/test/JDBC/expected/BABEL-1309-vu-verify.out index 471be43467..4f9a298153 100644 --- a/test/JDBC/expected/BABEL-1309-vu-verify.out +++ b/test/JDBC/expected/BABEL-1309-vu-verify.out @@ -13,10 +13,6 @@ go exec sp_updatestats resample; go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "resample" does not exist)~~ - exec sp_updatestats @resample; go diff --git a/test/JDBC/expected/BABEL-1309.out b/test/JDBC/expected/BABEL-1309.out index f3443e4d00..e3fad04741 100644 --- a/test/JDBC/expected/BABEL-1309.out +++ b/test/JDBC/expected/BABEL-1309.out @@ -13,10 +13,6 @@ go exec sp_updatestats resample; go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "resample" does not exist)~~ - exec sp_updatestats @resample; go diff --git a/test/JDBC/expected/BABEL-1524.out b/test/JDBC/expected/BABEL-1524.out index 8f94ae18d6..bbc3c9bf08 100644 --- a/test/JDBC/expected/BABEL-1524.out +++ b/test/JDBC/expected/BABEL-1524.out @@ -333,5 +333,14 @@ ok drop table t1; go +-- Test BABEL-4433 +CREATE TABLE t( c timestamp NOT NULL, PRIMARY KEY ( [ID] ASC)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "id" named in key does not exist)~~ + + + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; go diff --git a/test/JDBC/expected/BABEL-1591.out b/test/JDBC/expected/BABEL-1591.out new file mode 100644 index 0000000000..c522c33999 --- /dev/null +++ b/test/JDBC/expected/BABEL-1591.out @@ -0,0 +1,131 @@ + +-- 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.)~~ + + +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 + +DROP FUNCTION IF EXISTS foorollbacktest +GO + +DROP FUNCTION IF EXISTS fooexecutetest +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/expected/BABEL-1603.out b/test/JDBC/expected/BABEL-1603.out index f5450b0b8f..a8c7fb6ddf 100644 --- a/test/JDBC/expected/BABEL-1603.out +++ b/test/JDBC/expected/BABEL-1603.out @@ -33,6 +33,27 @@ int ~~END~~ + +DECLARE @rc INT = 3; +SET DATEFIRST @rc; +GO + +SELECT @@DATEFIRST; +GO +~~START~~ +int +3 +~~END~~ + + +SELECT DATEPART(weekday, CAST( '2021-12-31' as DATE)); +GO +~~START~~ +int +3 +~~END~~ + + -- reset it to 7 SET DATEFIRST 7 GO @@ -68,6 +89,38 @@ GO ~~ERROR (Message: 8 is outside the valid range for parameter "babelfishpg_tsql.datefirst" (1 .. 7))~~ +SET DATEFIRST NULL; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "NULL")~~ + + +DECLARE @rc INT = 0; +SET DATEFIRST @rc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 0 is outside the valid range for parameter "babelfishpg_tsql.datefirst" (1 .. 7))~~ + + +DECLARE @rc INT = 8; +SET DATEFIRST @rc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 8 is outside the valid range for parameter "babelfishpg_tsql.datefirst" (1 .. 7))~~ + + + +DECLARE @rc INT = NULL; +SET DATEFIRST @rc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid argument for SET DATEFIRST. Must be a non-null value.)~~ + + SELECT @@DATEFIRST; GO ~~START~~ 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-1636.out b/test/JDBC/expected/BABEL-1636.out index 2d1c55b73b..48ef69b8cb 100644 --- a/test/JDBC/expected/BABEL-1636.out +++ b/test/JDBC/expected/BABEL-1636.out @@ -14,9 +14,10 @@ exec p1 go ~~ROW COUNT: 1~~ -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: ROLLBACK statement with active table variables is not yet supported.)~~ +~~START~~ +int#!#int +1#!#2 +~~END~~ -- ROLLBACK should get unsupported error message @@ -35,9 +36,10 @@ int 1 ~~END~~ -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: ROLLBACK statement with active table variables is not yet supported.)~~ +~~START~~ +int +1 +~~END~~ declare @tv1 tableType; @@ -79,9 +81,11 @@ int#!#int 4#!#3 ~~END~~ -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: ROLLBACK statement with active table variables is not yet supported.)~~ +~~START~~ +int#!#int +3#!#4 +4#!#3 +~~END~~ -- cleanup 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/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/BABEL-2089.out b/test/JDBC/expected/BABEL-2089.out index fced99d987..32dc137aec 100644 --- a/test/JDBC/expected/BABEL-2089.out +++ b/test/JDBC/expected/BABEL-2089.out @@ -369,7 +369,7 @@ go select * from babel_2089_OpsDbView go ~~START~~ -int#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#int#!#nvarchar#!#int#!#int#!#nvarchar#!#int#!#int#!#int#!#int#!#varchar#!#datetime2#!#int#!#int#!#int#!#int#!#int#!#datetime2#!#int#!#varchar#!#varchar#!#int#!#varchar#!#int#!#varchar +int#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#nvarchar#!#nvarchar#!#nvarchar#!#int#!#int#!#nvarchar#!#int#!#int#!#nvarchar#!#int#!#int#!#int#!#int#!#varchar#!#datetime2#!#int#!#int#!#int#!#int#!#int#!#datetime2#!#int#!#varchar#!#varchar#!#int#!#nvarchar#!#int#!#varchar ~~END~~ diff --git a/test/JDBC/expected/BABEL-2144-vu-cleanup.out b/test/JDBC/expected/BABEL-2144-vu-cleanup.out new file mode 100644 index 0000000000..de975e0245 --- /dev/null +++ b/test/JDBC/expected/BABEL-2144-vu-cleanup.out @@ -0,0 +1,7 @@ +drop view babel_2144_vu_prepare_v1; +go +drop table babel_2144_vu_prepare_t1; +go +drop table babel_2144_vu_prepare_t2; +go + diff --git a/test/JDBC/expected/BABEL-2144-vu-prepare.out b/test/JDBC/expected/BABEL-2144-vu-prepare.out new file mode 100644 index 0000000000..a676d12348 --- /dev/null +++ b/test/JDBC/expected/BABEL-2144-vu-prepare.out @@ -0,0 +1,23 @@ +create table babel_2144_vu_prepare_t1(c1 int, c2 int); +go +create table babel_2144_vu_prepare_t2(c1 int, c2 int); +go +insert into babel_2144_vu_prepare_t1 values (12,15); +go +~~ROW COUNT: 1~~ + +insert into babel_2144_vu_prepare_t1 values (0,0); +go +~~ROW COUNT: 1~~ + +insert into babel_2144_vu_prepare_t2 values (13,16); +go +~~ROW COUNT: 1~~ + +insert into babel_2144_vu_prepare_t2 values (0,0); +go +~~ROW COUNT: 1~~ + +CREATE VIEW babel_2144_vu_prepare_v1 AS SELECT * FROM babel_2144_vu_prepare_t2 WHERE c2 > 10; +go + diff --git a/test/JDBC/expected/BABEL-2144-vu-verify.out b/test/JDBC/expected/BABEL-2144-vu-verify.out new file mode 100644 index 0000000000..66eec64e1e --- /dev/null +++ b/test/JDBC/expected/BABEL-2144-vu-verify.out @@ -0,0 +1,97 @@ +UPDATE babel_2144_vu_prepare_t1 SET c1 = 23 OUTPUT INSERTED.c2, 22 INTO babel_2144_vu_prepare_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The target 'babel_2144_vu_prepare_v1' of the OUTPUT INTO clause cannot be a view or common table expression.)~~ + +UPDATE babel_2144_vu_prepare_t2 SET c1 = 0 OUTPUT INSERTED.c2, 22 INTO babel_2144_vu_prepare_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The target 'babel_2144_vu_prepare_v1' of the OUTPUT INTO clause cannot be a view or common table expression.)~~ + +UPDATE babel_2144_vu_prepare_t2 SET c1 = 23 OUTPUT INSERTED.c2, 22 INTO babel_2144_vu_prepare_t2; +go +~~ROW COUNT: 2~~ + +UPDATE babel_2144_vu_prepare_t2 SET c1 = 0 OUTPUT INSERTED.c1, 33 INTO babel_2144_vu_prepare_t2; +go +~~ROW COUNT: 4~~ + +UPDATE babel_2144_vu_prepare_t1 SET c1 = 1 OUTPUT INSERTED.c2, 11 INTO babel_2144_vu_prepare_t1; +go +~~ROW COUNT: 2~~ + +UPDATE babel_2144_vu_prepare_t1 SET c1 = 2 OUTPUT INSERTED.c1, 1 INTO babel_2144_vu_prepare_t2; +go +~~ROW COUNT: 4~~ + +INSERT INTO babel_2144_vu_prepare_t1 OUTPUT INSERTED.c2, 22 INTO babel_2144_vu_prepare_v1 (c1, c2) VALUES (23,22); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The target 'babel_2144_vu_prepare_v1' of the OUTPUT INTO clause cannot be a view or common table expression.)~~ + +INSERT INTO babel_2144_vu_prepare_t2 OUTPUT INSERTED.c2, 22 INTO babel_2144_vu_prepare_t1 (c1, c2) VALUES (23,22); +go +~~ROW COUNT: 1~~ + +INSERT INTO babel_2144_vu_prepare_t1 OUTPUT INSERTED.c2, 22 INTO babel_2144_vu_prepare_t2 (c1, c2) VALUES (23,22); +go +~~ROW COUNT: 1~~ + +delete babel_2144_vu_prepare_t1 output deleted.c1 into babel_2144_vu_prepare_v1(c1); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The target 'babel_2144_vu_prepare_v1' of the OUTPUT INTO clause cannot be a view or common table expression.)~~ + +delete babel_2144_vu_prepare_t2 output deleted.c1 into babel_2144_vu_prepare_t1(c1); +go +~~ROW COUNT: 14~~ + +delete babel_2144_vu_prepare_t2 output deleted.c1 into babel_2144_vu_prepare_v1(c1); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The target 'babel_2144_vu_prepare_v1' of the OUTPUT INTO clause cannot be a view or common table expression.)~~ + +select * from babel_2144_vu_prepare_t1; +go +~~START~~ +int#!#int +2#!#15 +2#!#11 +2#!#0 +2#!#11 +22#!#22 +23#!#22 +0#!# +0#!# +0#!# +0#!# +0#!# +0#!# +0#!# +0#!# +2#!# +2#!# +2#!# +2#!# +23#!# +22#!# +~~END~~ + +select * from babel_2144_vu_prepare_t2; +go +~~START~~ +int#!#int +~~END~~ + +select * from babel_2144_vu_prepare_v1; +go +~~START~~ +int#!#int +~~END~~ + + diff --git a/test/JDBC/expected/BABEL-2170-vu-cleanup.out b/test/JDBC/expected/BABEL-2170-vu-cleanup.out new file mode 100644 index 0000000000..9fd916b30f --- /dev/null +++ b/test/JDBC/expected/BABEL-2170-vu-cleanup.out @@ -0,0 +1,39 @@ +-- clean all objects in first database +USE db1_BABEL2170; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_insert; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_update; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_delete; +GO + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_bulkinsert; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view_bulkinsert; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view_2; +GO + +DROP TABLE IF EXISTS babel_2170_vu_employees; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view_txn; +GO + +DROP TABLE IF EXISTS babel_2170_vu_employees_txn; +GO + +USE MASTER; +GO + +DROP DATABASE IF EXISTS db1_BABEL2170; +GO diff --git a/test/JDBC/expected/BABEL-2170-vu-prepare.out b/test/JDBC/expected/BABEL-2170-vu-prepare.out new file mode 100644 index 0000000000..dc6cd1a8cc --- /dev/null +++ b/test/JDBC/expected/BABEL-2170-vu-prepare.out @@ -0,0 +1,105 @@ +-- We will create two databases db1_BABEL2170, db2_BABEL2170 +CREATE DATABASE db1_BABEL2170; +GO + +USE db1_BABEL2170; +GO + +CREATE TABLE babel_2170_vu_employees +( + EmployeeID int NOT NULL, + EmployeeName VARCHAR(50), + EmployeeAddress VARCHAR(50), + MonthSalary NUMERIC(10, 2) +) +GO + +INSERT INTO babel_2170_vu_employees VALUES(1, 'amber', '1st Street', '1000'); +INSERT INTO babel_2170_vu_employees VALUES(2, 'angel', '1st Street', '2000'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE VIEW babel_2170_vu_employees_view AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees +WHERE EmployeeName LIKE 'a%'; +GO + +CREATE VIEW babel_2170_vu_employees_view_bulkinsert AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees +WHERE EmployeeName LIKE 'b%'; +GO + +CREATE VIEW babel_2170_vu_employees_view_2 AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees +WHERE EmployeeName LIKE 'a%'; +GO + +CREATE SCHEMA schema_2170; +GO + +CREATE TABLE schema_2170.babel_2170_vu_employees +( + EmployeeID int NOT NULL, + EmployeeName VARCHAR(50), + EmployeeAddress VARCHAR(50), + MonthSalary NUMERIC(10, 2) +) +GO + +INSERT INTO schema_2170.babel_2170_vu_employees VALUES(1, 'amber', '1st Street', '1000'); +INSERT INTO schema_2170.babel_2170_vu_employees VALUES(2, 'angel', '1st Street', '2000'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE VIEW schema_2170.babel_2170_vu_employees_view AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM schema_2170.babel_2170_vu_employees +WHERE EmployeeName LIKE 'a%'; +GO + +CREATE TABLE babel_2170_vu_employees_txn +( + EmployeeID int NOT NULL, + EmployeeName VARCHAR(50), + EmployeeAddress VARCHAR(50), + MonthSalary NUMERIC(10, 2) +) +GO + +INSERT INTO babel_2170_vu_employees_txn VALUES(1, 'amber', '1st Street', '1000'); +INSERT INTO babel_2170_vu_employees_txn VALUES(2, 'angel', '1st Street', '2000'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE VIEW babel_2170_vu_employees_view_txn AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees_txn +WHERE EmployeeName LIKE 'a%'; +GO diff --git a/test/JDBC/expected/BABEL-2170-vu-verify.out b/test/JDBC/expected/BABEL-2170-vu-verify.out new file mode 100644 index 0000000000..94e3ee9a16 --- /dev/null +++ b/test/JDBC/expected/BABEL-2170-vu-verify.out @@ -0,0 +1,578 @@ +USE db1_BABEL2170; +GO + +-- Instead of Insert Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_insert ON babel_2170_vu_employees_view +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked' +END +GO + +INSERT INTO babel_2170_vu_employees_view VALUES(3, 'adam', '1st Street', '3000'); +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view; +GO +~~START~~ +int +2 +~~END~~ + + +-- Instead of Update Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view +INSTEAD OF UPDATE +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked' +END +GO + +UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID,EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID = 2 ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +BEGIN TRANSACTION + UPDATE babel_2170_vu_employees_view SET MonthSalary = MonthSalary +1 WHERE EmployeeID IN (1, 2); +COMMIT TRANSACTION; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 2~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees WHERE EmployeeID IN (1, 2) ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +-- Instead of Delete Trigger on View +CREATE TRIGGER babel_2170_vu_employees_view_iot_delete ON babel_2170_vu_employees_view +INSTEAD OF DELETE +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_delete Invoked' +END +GO + +BEGIN TRANSACTION + DELETE FROM babel_2170_vu_employees_view WHERE EmployeeID IN (1, 2); +COMMIT TRANSACTION; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_delete Invoked +~~END~~ + +~~ROW COUNT: 2~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees_view; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT COUNT(EmployeeID) FROM babel_2170_vu_employees; +GO +~~START~~ +int +2 +~~END~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +--- Tests multiple insert queries and check if inserted table can be accessed and trigger is working fine. +CREATE TRIGGER babel_2170_vu_employees_view_iot_bulkinsert ON babel_2170_vu_employees_view_bulkinsert +INSTEAD OF INSERT +AS + SELECT * FROM INSERTED; +GO + +BEGIN TRANSACTION +DECLARE @i int = 1 + WHILE @i <= 3 + BEGIN + INSERT INTO babel_2170_vu_employees_view_bulkinsert VALUES(@i, 'bob', '1st Street', '1000'); + SET @i = @i + 1 + END +COMMIT TRANSACTION +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#bob#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +2#!#bob#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +3#!#bob#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Same trigger name on different View created on Same table in same schema +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees_view_2 +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view2_iot_update Invoked' +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: trigger "babel_2170_vu_employees_view_iot_update" already exists in the database)~~ + + +-- Same trigger name on a Table in same schema +CREATE TRIGGER babel_2170_vu_employees_view_iot_update ON babel_2170_vu_employees +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees__table_iot_update Invoked' +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: trigger "babel_2170_vu_employees_view_iot_update" already exists in the database)~~ + + + +-- Test Instead of Update trigger in same db but cross schema +-- Cleanup default dbo schema IO Update trigger +DROP TRIGGER IF EXISTS [dbo].[babel_2170_vu_employees_view_iot_update]; +GO + +CREATE TRIGGER [schema_2170].[babel_2170_vu_employees_view_iot_update] ON [schema_2170].[babel_2170_vu_employees_view] +INSTEAD OF UPDATE +AS + SELECT 'Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked' +GO + +CREATE TRIGGER [babel_2170_vu_employees_view_iot_update] ON [babel_2170_vu_employees_view] +INSTEAD OF UPDATE +AS + SELECT 'Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked' +GO + +UPDATE [schema_2170].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM [schema_2170].[babel_2170_vu_employees_view] ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +UPDATE [dbo].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.dbo.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM [dbo].[babel_2170_vu_employees_view] ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +-- drop dbo schema trigger and test that schema_2170.update trigger is not dropped +DROP TRIGGER IF EXISTS [dbo].[babel_2170_vu_employees_view_iot_update]; +GO + +UPDATE [schema_2170].[babel_2170_vu_employees_view] SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger db1_BABEL2170.schema_2170.babel_2170_vu_employees_view_iot_update Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- schema_2170 object cleanup +DROP TRIGGER IF EXISTS [schema_2170].babel_2170_vu_employees_view_iot_update; +GO + +DROP VIEW IF EXISTS [schema_2170].babel_2170_vu_employees_view; +GO + +DROP TABLE IF EXISTS [schema_2170].babel_2170_vu_employees; +GO + +DROP SCHEMA IF EXISTS schema_2170; +GO + +-- Test Transaction Commit and Rollback inside Instead of triggers +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn +INSTEAD OF UPDATE +AS + BEGIN + BEGIN TRAN; + INSERT INTO babel_2170_vu_employees_view_txn VALUES(3, 'adam', '1st Street', '3000'); + COMMIT tran; + END +GO + +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn +INSTEAD OF UPDATE +AS + BEGIN + BEGIN TRAN; + INSERT INTO babel_2170_vu_employees_view_txn VALUES(3, 'adam', '1st Street', '3000'); + ROLLBACK tran; + END +GO + +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 3609)~~ + +~~ERROR (Message: The transaction ended in the trigger. The batch has been aborted.)~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_insert ON babel_2170_vu_employees_view_txn INSTEAD OF INSERT AS +BEGIN TRAN; +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +COMMIT; +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +SELECT * FROM inserted; +GO + +BEGIN TRAN; +GO +INSERT INTO babel_2170_vu_employees_view_txn VALUES(4, 'ana', '1st Street', '4000'); +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +4#!#ana#!#1st Street#!#4000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +COMMIT; +GO + +BEGIN TRAN +GO +INSERT INTO babel_2170_vu_employees_view_txn VALUES(4, 'ana', '1st Street', '4000'); +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2002.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +4#!#ana#!#1st Street#!#4000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +IF (@@trancount > 0) ROLLBACK; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_insert; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_update ON babel_2170_vu_employees_view_txn INSTEAD OF UPDATE AS +SAVE TRAN sp1; +SAVE TRAN sp2; +DELETE FROM babel_2170_vu_employees_view_txn where EmployeeID =2; +ROLLBACK TRAN sp1; +GO + +BEGIN TRAN +GO +SELECT @@trancount; +UPDATE babel_2170_vu_employees_view_txn SET MonthSalary = MonthSalary +1 WHERE EmployeeID = 2; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +IF (@@trancount > 0) ROLLBACK; +GO + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_update; +GO + +CREATE TRIGGER babel_2170_vu_employees_view_iot_txn_delete ON babel_2170_vu_employees_view_txn INSTEAD OF DELETE AS +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +INSERT INTO babel_2170_vu_employees_view_txn VALUES(5, 'ash', '1st Street', '5000'); +SELECT * FROM deleted; +GO + +DELETE FROM babel_2170_vu_employees_view_txn where EmployeeID =1; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view_txn ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2001.00 +3#!#adam#!#1st Street#!#3000.00 +5#!#ash#!#1st Street#!#5000.00 +~~END~~ + + +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_txn_delete; +GO + +-- test multi-db mode +SELECT set_config('role', 'jdbc_user', false); +GO +~~START~~ +text +jdbc_user +~~END~~ + + +SELECT set_config('babelfishpg_tsql.migration_mode', 'multi-db', false); +GO +~~START~~ +text +multi-db +~~END~~ + + +CREATE DATABASE db2_BABEL2170; +GO + +USE db2_BABEL2170; +GO + +CREATE TABLE babel_2170_vu_employees +( + EmployeeID int NOT NULL, + EmployeeName VARCHAR(50), + EmployeeAddress VARCHAR(50), + MonthSalary NUMERIC(10, 2) +) +GO + +INSERT INTO babel_2170_vu_employees VALUES(1, 'amber', '1st Street', '1000'); +INSERT INTO babel_2170_vu_employees VALUES(2, 'angel', '1st Street', '2000'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE VIEW babel_2170_vu_employees_view AS +SELECT EmployeeID, + EmployeeName, + EmployeeAddress, + MonthSalary +FROM babel_2170_vu_employees +WHERE EmployeeName LIKE 'a%'; +GO + +-- create same name Instead of Insert trigger in second db to test Cross db behavior +CREATE TRIGGER babel_2170_vu_employees_view_iot_insert ON babel_2170_vu_employees_view +INSTEAD OF INSERT +AS +BEGIN + SELECT 'Trigger db2_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked' +END +GO + +-- should fire IOT trigger of second db +INSERT INTO babel_2170_vu_employees_view VALUES(3, 'adam', '1st Street db2_BABEL2170', '3000'); +GO +~~START~~ +varchar +Trigger db2_BABEL2170.dbo.babel_2170_vu_employees_view_iot_insert Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +SELECT EmployeeID, EmployeeName, EmployeeAddress, MonthSalary FROM babel_2170_vu_employees_view ORDER BY EmployeeID; +GO +~~START~~ +int#!#varchar#!#varchar#!#numeric +1#!#amber#!#1st Street#!#1000.00 +2#!#angel#!#1st Street#!#2000.00 +~~END~~ + + +-- clean all objects in second database +DROP TRIGGER IF EXISTS babel_2170_vu_employees_view_iot_insert; +GO + +DROP VIEW IF EXISTS babel_2170_vu_employees_view; +GO + +DROP TABLE IF EXISTS babel_2170_vu_employees; +GO + +USE MASTER; +GO + +DROP DATABASE IF EXISTS db2_BABEL2170; +GO 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 diff --git a/test/JDBC/expected/BABEL-2325.out b/test/JDBC/expected/BABEL-2325.out index bf0c2c1aa4..ea9f38ef34 100644 --- a/test/JDBC/expected/BABEL-2325.out +++ b/test/JDBC/expected/BABEL-2325.out @@ -27,12 +27,13 @@ string ~~END~~ --- should report error (double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF) +-- should return f'oo with QUOTED_IDENTIFIER=OFF SELECT "f'oo" GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: double-quoted string literals cannot contain single-quotes while QUOTED_IDENTIFIER=OFF)~~ +~~START~~ +varchar +f'oo +~~END~~ 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-2372.out b/test/JDBC/expected/BABEL-2372.out index 87a1994737..c8fb096fa1 100644 --- a/test/JDBC/expected/BABEL-2372.out +++ b/test/JDBC/expected/BABEL-2372.out @@ -12,6 +12,18 @@ GO SET LANGUAGE us_english GO +declare @rc varchar(10) = 'Italian'; +SET LANGUAGE @rc +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Settings other than "us_english" are not allowed for option LANGUAGE. Please use babelfishpg_tsql.escape_hatch_session_settings to ignore)~~ + + +declare @rc varchar(10) = 'us_english'; +SET LANGUAGE @rc +go + EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_session_settings', 'ignore'; GO @@ -20,3 +32,28 @@ GO SET LANGUAGE us_english GO + + +declare @rc varchar(10) = 'Italian'; +SET LANGUAGE @rc +go + +declare @rc varchar(10) = 'us_english'; +SET LANGUAGE @rc +go + + +declare @rc varchar(10) = NULL; +SET LANGUAGE @rc +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid argument for SET LANGUAGE. Must be a non-null value.)~~ + + +SET LANGUAGE NULL +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "NULL")~~ + 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-2449-vu-prepare.out b/test/JDBC/expected/BABEL-2449-vu-prepare.out index 8e84397f98..2f7f4aa948 100644 --- a/test/JDBC/expected/BABEL-2449-vu-prepare.out +++ b/test/JDBC/expected/BABEL-2449-vu-prepare.out @@ -168,3 +168,39 @@ BEGIN RETURN (SELECT DATETIMEOFFSETFROMPARTS(2011.9, 8.9, 15.9, 14.9, 30.9, 00, 500.9, 12.9, 30.9, 3)); END GO + +CREATE FUNCTION BABEL_2449_vu_prepare_f14() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATETIMEOFFSETFROMPARTS(1700, 8, 15, 14, 30, 00, 500, 12, 30, 3)); +END +GO + +CREATE FUNCTION BABEL_2449_vu_prepare_f15() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATETIMEOFFSETFROMPARTS(NULL, 8, 15, 14, 30, 00, 500, 12, 30, 3)); +END +GO + +CREATE FUNCTION BABEL_2449_vu_prepare_f16() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATETIMEOFFSETFROMPARTS(1, 8, 15, 14, 30, 00, 500, 12, 30, 3)); +END +GO + +CREATE FUNCTION BABEL_2449_vu_prepare_f17() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (SELECT DATETIMEOFFSETFROMPARTS(0*1, 8, 15, 14, 30, 00, 500, 12, 30, 3)); +END +GO + +CREATE FUNCTION BABEL_2449_vu_prepare_f18() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN ( Select DATETIMEOFFSETFROMPARTS(1, 1, 1, 4, 30, 00, 500, 12, 30, 3)); +END +GO + diff --git a/test/JDBC/expected/BABEL-2449-vu-verify.out b/test/JDBC/expected/BABEL-2449-vu-verify.out index be637021c5..c9f81bfa70 100644 --- a/test/JDBC/expected/BABEL-2449-vu-verify.out +++ b/test/JDBC/expected/BABEL-2449-vu-verify.out @@ -371,3 +371,55 @@ datetimeoffset DROP FUNCTION BABEL_2449_vu_prepare_f13 GO + +SELECT BABEL_2449_vu_prepare_f14() +GO +~~START~~ +datetimeoffset +1700-08-15 14:30:00.5000000 +12:30 +~~END~~ + +DROP FUNCTION BABEL_2449_vu_prepare_f14 +GO + +SELECT BABEL_2449_vu_prepare_f15() +GO +~~START~~ +datetimeoffset + +~~END~~ + +DROP FUNCTION BABEL_2449_vu_prepare_f15 +GO + +SELECT BABEL_2449_vu_prepare_f16() +GO +~~START~~ +datetimeoffset +0001-08-15 14:30:00.5000000 +12:30 +~~END~~ + +DROP FUNCTION BABEL_2449_vu_prepare_f16 +GO + +SELECT BABEL_2449_vu_prepare_f17() +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type datetimeoffset, some of the arguments have values which are not valid.)~~ + +DROP FUNCTION BABEL_2449_vu_prepare_f17 +GO + +SELECT BABEL_2449_vu_prepare_f18() +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type datetimeoffset, some of the arguments have values which are not valid.)~~ + +DROP FUNCTION BABEL_2449_vu_prepare_f18 +GO 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/BABEL-2551.out b/test/JDBC/expected/BABEL-2551.out new file mode 100644 index 0000000000..296f5743cf --- /dev/null +++ b/test/JDBC/expected/BABEL-2551.out @@ -0,0 +1,287 @@ +create table babel2551_t1(a int); +create table babel2551_t2(a int); +go + +BEGIN TRAN +insert babel2551_t1 values (1), (1), (3), (null); +insert into babel2551_t2 select top(3) a from babel2551_t1 order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int + +1 +1 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (1), (1), (1), (2); +insert into babel2551_t2 select distinct top(2) a from babel2551_t1 order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 5~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +1 +2 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert top(2) into babel2551_t2 select top(3) a from babel2551_t1 order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +1 +2 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert into babel2551_t2 select top(2) s.a from (select top(3) a from babel2551_t1 order by 1) s order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +1 +2 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert into babel2551_t2 select top(2) a from babel2551_t1 where a in (select top(3) a from babel2551_t1 order by 1) order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +1 +2 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert babel2551_t2 values (2), (3), (4), (5); +insert into babel2551_t2 select top(2) t1.a from babel2551_t1 t1 join babel2551_t2 t2 on t1.a = t2.a order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +2 +2 +3 +3 +4 +5 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert babel2551_t2 values (2), (3), (4), (5); +insert into babel2551_t2 select distinct top(2) t1.a from babel2551_t1 t1 cross join babel2551_t2 t2 order by t1.a; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +1 +2 +2 +3 +4 +5 +~~END~~ + + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert into babel2551_t2 select top(2) t1.a into babel2551_t3 from babel2551_t1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SELECT ... INTO is not allowed here)~~ + + +create view babel2551_view as select a from babel2551_t1; +GO + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert into babel2551_t2 select top(3) a from babel2551_view order by 1; +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +1 +2 +3 +~~END~~ + + +drop view babel2551_view +GO + +create function babel2551_cross_appy_func(@a int) returns @ret table(a int) as +BEGIN + insert into @ret select top(1) a from babel2551_t1 where a = @a + return +END; +GO + +BEGIN TRAN +insert babel2551_t1 values (1), (2), (3), (4); +insert babel2551_t2 values (2), (3), (4), (5); +insert into babel2551_t2 select top(2) t1.a +from babel2551_t1 t1 cross apply babel2551_cross_appy_func(t1.a); +select * from babel2551_t2 order by 1; +ROLLBACK +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int +1 +2 +2 +3 +4 +5 +~~END~~ + + +drop function babel2551_cross_appy_func; +GO + +drop table babel2551_t1; +drop table babel2551_t2; +GO + +declare @2551_top_const INT = 2; +declare @2551_tbl_var as table (a VARCHAR(15)); +insert into @2551_tbl_var values ('a'), ('b'), ('c'), ('d') +insert into @2551_tbl_var select top(@2551_top_const) tbl.a from @2551_tbl_var tbl; +select * from @2551_tbl_var order by a; +GO +~~ROW COUNT: 4~~ + +~~ROW COUNT: 2~~ + +~~START~~ +varchar +a +a +b +b +c +d +~~END~~ + + +-- BABEL-3312 Case +CREATE TABLE babel2551_t1(c1 int, c2 int) +CREATE TABLE babel2551_t2(c1 int, c2 int, c3 int) +GO +INSERT INTO babel2551_t1(c1, c2) VALUES(1, 10) +INSERT INTO babel2551_t1(c1, c2) VALUES(2, 20) +INSERT INTO babel2551_t2(c1, c2, c3) VALUES(1, 1, 100) +INSERT INTO babel2551_t2(c1, c2, c3) VALUES(1, 2, 1001) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +--Multi-statement function with TOP +CREATE FUNCTION myMSTVF(@a int) +RETURNS @ret table (a int) +AS +BEGIN +INSERT INTO @ret +SELECT TOP(2) c1 +FROM babel2551_t2 +WHERE babel2551_t2.c1 = @a +RETURN +END +GO + +SELECT * FROM babel2551_t1 CROSS APPLY myMSTVF(babel2551_t1.c1) +GO +~~START~~ +int#!#int#!#int +1#!#10#!#1 +1#!#10#!#1 +~~END~~ + + +SELECT * FROM myMSTVF(1) +GO +~~START~~ +int +1 +1 +~~END~~ + + +DROP FUNCTION myMSTVF +DROP TABLE babel2551_t1 +DROP TABLE babel2551_t2 +GO diff --git a/test/JDBC/expected/BABEL-2619-vu-cleanup.out b/test/JDBC/expected/BABEL-2619-vu-cleanup.out new file mode 100644 index 0000000000..f03fb6faa3 --- /dev/null +++ b/test/JDBC/expected/BABEL-2619-vu-cleanup.out @@ -0,0 +1,11 @@ +drop table if exists babel_2619_t1 +drop table if exists babel_2619_t2 +drop table if exists babel_2619_t3 +drop table if exists babel_2619_t4 +drop table if exists babel_2619_t5_1 +drop table if exists babel_2619_t5_2 +drop table if exists babel_2619_t5_3 +drop table if exists babel_2619_t6_1 +drop table if exists babel_2619_t6_2 +drop table if exists babel_2619_t6_3 +go diff --git a/test/JDBC/expected/BABEL-2619-vu-prepare.out b/test/JDBC/expected/BABEL-2619-vu-prepare.out new file mode 100644 index 0000000000..5be9ec023c --- /dev/null +++ b/test/JDBC/expected/BABEL-2619-vu-prepare.out @@ -0,0 +1,11 @@ +create table babel_2619_t1(a int not null, b int null) +create table babel_2619_t2(a int not null, b int null) +create table babel_2619_t3(a int not null, b int null) +create table babel_2619_t4(a int not null, b int null) +create table babel_2619_t5_1(a int not null, b int null) +create table babel_2619_t5_2(a int not null, b int null) +create table babel_2619_t5_3(a int not null, b int null) +create table babel_2619_t6_1(a int not null, b int null) +create table babel_2619_t6_2(a int not null, b int null) +create table babel_2619_t6_3(a int not null, b int null) +go diff --git a/test/JDBC/expected/BABEL-2619-vu-verify.out b/test/JDBC/expected/BABEL-2619-vu-verify.out new file mode 100644 index 0000000000..a0f40d543e --- /dev/null +++ b/test/JDBC/expected/BABEL-2619-vu-verify.out @@ -0,0 +1,193 @@ + +-- Tests to check whether error will be raised in case of creation of unique constraint/index on nullable column +-- Test 1: trying to create unique constraint on nullable and non null columns +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to STRICT (Default value) +create table babel_2619_v_t1(a int null, b int null unique, c int not null) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +create table babel_2619_v_t2(a int null, b int not null unique, c int not null) +go + +create table babel_2619_v_t3(a int null, b int unique, c int not null) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +create table babel_2619_v_t4(a int null, b int not null, unique(a)) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +create table babel_2619_v_t5(a int null, b int not null, unique(b)) +go + +create table babel_2619_v_t6(a int not null, b int null, c int not null, unique(a, b, c)) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +create table babel_2619_v_t7(a int not null, b int null, c int not null, unique(a, c)) +go + +drop table if exists babel_2619_v_t1; +drop table if exists babel_2619_v_t2; +drop table if exists babel_2619_v_t3; +drop table if exists babel_2619_v_t4; +drop table if exists babel_2619_v_t5; +drop table if exists babel_2619_v_t6; +drop table if exists babel_2619_v_t7; +go + +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to IGNORE +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +go + +create table babel_2619_v_t8(a int null, b int null unique, c int not null) +go + +create table babel_2619_v_t9(a int null, b int not null unique, c int not null) +go + +create table babel_2619_v_t10(a int null, b int unique, c int not null) +go + +create table babel_2619_v_t11(a int null, b int not null, unique(a)) +go + +create table babel_2619_v_t12(a int null, b int not null, unique(b)) +go + +create table babel_2619_v_t13(a int not null, b int null, c int not null, unique(a, b, c)) +go + +create table babel_2619_v_t14(a int not null, b int null, c int not null, unique(a, c)) +go + +drop table if exists babel_2619_v_t8; +drop table if exists babel_2619_v_t9; +drop table if exists babel_2619_v_t10; +drop table if exists babel_2619_v_t11; +drop table if exists babel_2619_v_t12; +drop table if exists babel_2619_v_t13; +drop table if exists babel_2619_v_t14; +go + +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +go + +-- Test 2: trying to creating unique index on nullable and non null columns +-- Table definition: babel_2619_t1(a int not null, b int null) +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to STRICT (Default value) +create unique index ix1 on babel_2619_t1(a) +go + +create unique index ix2 on babel_2619_t1(b) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE index is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +create unique index ix3 on babel_2619_t1(a,b) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE index is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +-- Table definition: babel_2619_t2(a int not null, b int null) +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to IGNORE +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +go + +create unique index ix1 on babel_2619_t2(a) +go + +create unique index ix2 on babel_2619_t2(b) +go + +create unique index ix3 on babel_2619_t2(a,b) +go + +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +go + + +-- Test 3: trying to alter table to add a column with unique contraint on nullable and non null columns +-- Table definition: babel_2619_t3(a int not null, b int null) +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to STRICT (Default value) +alter table babel_2619_t3 add col_c int null unique; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +alter table babel_2619_t3 add col_d int not null unique; +go + +-- Table definition: babel_2619_t4(a int not null, b int null) +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to IGNORE +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +go + +alter table babel_2619_t4 add col_c int null unique; +go + +alter table babel_2619_t4 add col_d int not null unique; +go + +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +go + + +-- Test 4: trying to alter table to add unique contraint on nullable and non null columns +-- Table definition: babel_2619_t5_1(a int not null, b int null), +-- babel_2619_t5_2(a int not null, b int null), +-- babel_2619_t5_3(a int not null, b int null) +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to STRICT (Default value) +alter table babel_2619_t5_1 add constraint uq_a unique (a); +go + +alter table babel_2619_t5_2 add constraint uq_b unique (b); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +alter table babel_2619_t5_3 add constraint uq_ab unique (a, b); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Nullable UNIQUE constraint is not supported. Please use babelfishpg_tsql.escape_hatch_unique_constraint to ignore or add a NOT NULL constraint)~~ + + +-- Table definition: babel_2619_t6_1(a int not null, b int null), +-- babel_2619_t6_2(a int not null, b int null), +-- babel_2619_t6_3(a int not null, b int null) +-- when babelfishpg_tsql.escape_hatch_unique_constraint is set to IGNORE +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'ignore'; +go + +alter table babel_2619_t6_1 add constraint uq_a unique (a); +go + +alter table babel_2619_t6_2 add constraint uq_b unique (b); +go + +alter table babel_2619_t6_3 add constraint uq_ab unique (a, b); +go + +exec sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_unique_constraint', 'strict'; +go diff --git a/test/JDBC/expected/BABEL-2688-vu-cleanup.out b/test/JDBC/expected/BABEL-2688-vu-cleanup.out new file mode 100644 index 0000000000..c814263870 --- /dev/null +++ b/test/JDBC/expected/BABEL-2688-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP TABLE babel_2688_tab1 +GO + +DROP FUNCTION babel_2688_fn1 +GO + +DROP FUNCTION babel_2688_fn3 +GO + +DROP FUNCTION babel_2688_fn4 +GO + +DROP FUNCTION babel_2688_fn6 +GO + +DROP FUNCTION babel_2688_fn7 +GO diff --git a/test/JDBC/expected/BABEL-2688-vu-prepare.out b/test/JDBC/expected/BABEL-2688-vu-prepare.out new file mode 100644 index 0000000000..a8d607672c --- /dev/null +++ b/test/JDBC/expected/BABEL-2688-vu-prepare.out @@ -0,0 +1,100 @@ + + + + +/* Example from JIRA */ +CREATE FUNCTION babel_2688_fn1() RETURNS @p TABLE (b bit) +AS +BEGIN + DECLARE @tv TABLE (b bit); + INSERT INTO @tv values (1); + UPDATE t + SET b = 0 + FROM @tv AS t; + INSERT INTO @p SELECT * FROM @tv; + RETURN; +END +GO + +CREATE TABLE babel_2688_tab1(a int) +GO + + +CREATE FUNCTION babel_2688_fn2() RETURNS int +AS +BEGIN + UPDATE t + SET a = 1 + FROM babel_2688_tab1 AS t; + RETURN 0; +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'UPDATE' cannot be used within a function)~~ + + + + + +CREATE FUNCTION babel_2688_fn3() RETURNS @t TABLE (a int) +AS +BEGIN + DECLARE @tv TABLE (a int); + INSERT INTO @tv values (1); + INSERT INTO @tv values (2); + INSERT INTO @tv values (3); + UPDATE @tv + SET a = 0 + WHERE a%2 = 1; + INSERT INTO @t SELECT * FROM @tv; + RETURN; +END +GO + +CREATE FUNCTION babel_2688_fn4() RETURNS @t TABLE (a int) +AS +BEGIN + UPDATE @tv_does_not_exist + SET a = 0; + RETURN; +END +GO + +CREATE FUNCTION babel_2688_fn5() RETURNS int +AS +BEGIN + DELETE FROM babel_2688_tab1; + RETURN 0; +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DELETE' cannot be used within a function)~~ + + + + + +CREATE FUNCTION babel_2688_fn6() RETURNS @t TABLE (a int) +AS +BEGIN + DECLARE @tv TABLE (a int); + + INSERT INTO @tv values (1); + INSERT INTO @tv values (2); + INSERT INTO @tv values (3); + DELETE FROM @tv + WHERE a%2 = 1; + INSERT INTO @t SELECT * FROM @tv; + RETURN; +END +GO + +CREATE FUNCTION babel_2688_fn7() RETURNS @t TABLE (a int) +AS +BEGIN + DELETE FROM @tv_does_not_exist; + RETURN; +END +GO diff --git a/test/JDBC/expected/BABEL-2688-vu-verify.out b/test/JDBC/expected/BABEL-2688-vu-verify.out new file mode 100644 index 0000000000..fb137332db --- /dev/null +++ b/test/JDBC/expected/BABEL-2688-vu-verify.out @@ -0,0 +1,43 @@ +SELECT * FROM babel_2688_fn1() +GO +~~START~~ +bit +0 +~~END~~ + + +SELECT * FROM babel_2688_fn3() +GO +~~START~~ +int +2 +0 +0 +~~END~~ + + +SELECT * FROM babel_2688_fn4() +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tv_does_not_exist" does not exist)~~ + + +SELECT * FROM babel_2688_fn6() +GO +~~START~~ +int +2 +~~END~~ + + +SELECT * FROM babel_2688_fn7() +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tv_does_not_exist" does not exist)~~ + diff --git a/test/JDBC/expected/BABEL-2805-vu-prepare.out b/test/JDBC/expected/BABEL-2805-vu-prepare.out index c83b5fb0ee..311f5b98eb 100644 --- a/test/JDBC/expected/BABEL-2805-vu-prepare.out +++ b/test/JDBC/expected/BABEL-2805-vu-prepare.out @@ -15,7 +15,7 @@ select t.* from babel_2805_vu_t1 CROSS APPLY ( VALUES - (1, 'col1', col1), + (1, CAST('col1' as TEXT), col1), (2, 'col2', col2) ) t(id, [name], [value]); go diff --git a/test/JDBC/expected/BABEL-2812-vu-verify.out b/test/JDBC/expected/BABEL-2812-vu-verify.out index af56128db0..7752d63442 100644 --- a/test/JDBC/expected/BABEL-2812-vu-verify.out +++ b/test/JDBC/expected/BABEL-2812-vu-verify.out @@ -282,7 +282,7 @@ SELECT * FROM babel_2812_vu_v32 GO ~~START~~ int -51 +52 ~~END~~ SELECT * FROM babel_2812_vu_v33 @@ -323,9 +323,9 @@ int -- should overflow SELECT * FROM babel_2812_vu_v38 GO -~~ERROR (Code: 8115)~~ +~~ERROR (Code: 535)~~ -~~ERROR (Message: integer out of range)~~ +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ -- smaller interval for millisecond SELECT * FROM babel_2812_vu_v39 @@ -338,9 +338,9 @@ int -- should overflow SELECT * FROM babel_2812_vu_v40 GO -~~ERROR (Code: 8115)~~ +~~ERROR (Code: 535)~~ -~~ERROR (Message: integer out of range)~~ +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ -- microsecond and nanosecond can only handle diff of 0 for date type SELECT * FROM babel_2812_vu_v41 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-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-2844.out b/test/JDBC/expected/BABEL-2844.out index 913f5650bc..e5ec6df10a 100644 --- a/test/JDBC/expected/BABEL-2844.out +++ b/test/JDBC/expected/BABEL-2844.out @@ -235,7 +235,7 @@ execute babel_2844_proc 3; go ~~START~~ text -Query Text: EXEC babel_2844_proc 3 +Query Text: EXEC babel_2844_proc 3 Query Text: insert babel_2844_t1 values (3, 3); -> Insert on babel_2844_t1 (cost=0.00..0.01 rows=0 width=0) -> Result (cost=0.00..0.01 rows=1 width=8) @@ -373,3 +373,101 @@ drop table babel_2844_t1; go drop table babel_2844_t2; go + +-- BABEL-3677: SELECT INTO +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +GO + +SET BABELFISH_SHOWPLAN_ALL ON; +GO + +-- should not crash +SELECT * INTO t3 FROM t1 WHERE t1.b = 1; +GO +~~START~~ +text +Query Text: SELECT * INTO t3 FROM t1 WHERE t1.b = 1 +~~END~~ + + +-- should fail with t3 does not exist because previous query was not executed +INSERT INTO t3 VALUES (1, 1), (2, 1), (3, 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "t3" does not exist)~~ + + +-- DMLs should also not be executed +INSERT INTO t1 VALUES (1, 1), (2, 1), (3, 1); +GO +~~START~~ +text +Query Text: INSERT INTO t1 VALUES (1, 1), (2, 1), (3, 1); +Insert on t1 (cost=0.00..0.04 rows=0 width=0) + -> Values Scan on "*VALUES*" (cost=0.00..0.04 rows=3 width=8) +~~END~~ + + +DELETE FROM t1 WHERE a = 3; +GO +~~START~~ +text +Query Text: DELETE FROM t1 WHERE a = 3; +Delete on t1 (cost=0.15..8.17 rows=0 width=0) + -> Index Scan using t1_pkey on t1 (cost=0.15..8.17 rows=1 width=6) + Index Cond: (a = 3) +~~END~~ + + +UPDATE t1 SET a = 2 WHERE a = 1; +GO +~~START~~ +text +Query Text: UPDATE t1 SET a = 2 WHERE a = 1; +Update on t1 (cost=0.15..8.17 rows=0 width=0) + -> Index Scan using t1_pkey on t1 (cost=0.15..8.17 rows=1 width=10) + Index Cond: (a = 1) +~~END~~ + + +-- also create function just for the sake of testing it +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + RETURN @TSQL +END +GO +~~START~~ +text +Query Text: CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + RETURN @TSQL +END +~~END~~ + + +-- function should not be created but should not crash +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function master_dbo.wosql_buildrevenuedetailoluquery() does not exist)~~ + + +SET BABELFISH_SHOWPLAN_ALL OFF; +GO + +-- should be empty +SELECT * FROM t1; +GO +~~START~~ +int#!#int +~~END~~ + + +DROP TABLE t1; +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/BABEL-2903.out b/test/JDBC/expected/BABEL-2903.out index 2b5c437661..3c4fabea92 100644 --- a/test/JDBC/expected/BABEL-2903.out +++ b/test/JDBC/expected/BABEL-2903.out @@ -58,9 +58,9 @@ Query Text: ASSIGN @a = SELECT 5 Query Text: ASSIGN @b = SELECT 5 Query Text: SELECT 5 -> Result (cost=0.00..0.01 rows=1 width=4) -Query Text: EXEC babel_2903_outer_proc @a, @b +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) @@ -74,17 +74,17 @@ 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) -> 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/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/expected/BABEL-2979.out b/test/JDBC/expected/BABEL-2979.out deleted file mode 100644 index 439a5c1087..0000000000 --- a/test/JDBC/expected/BABEL-2979.out +++ /dev/null @@ -1,6 +0,0 @@ -alter user john with login = smith -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'ALTER USER WITH LOGIN' is not currently supported in Babelfish)~~ - diff --git a/test/JDBC/expected/BABEL-2998.out b/test/JDBC/expected/BABEL-2998.out index af322b960e..e863194a08 100644 --- a/test/JDBC/expected/BABEL-2998.out +++ b/test/JDBC/expected/BABEL-2998.out @@ -4,18 +4,22 @@ SELECT CAST('1' AS CHAR(10)) AS Col1 UNION SELECT NULL AS Col1 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: The string size for the given CHAR/NCHAR data is not defined. Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n))~~ +~~START~~ +char +1 + +~~END~~ SELECT CAST('1' AS CHAR(10)) AS Col1 UNION ALL SELECT NULL AS Col1 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: The string size for the given CHAR/NCHAR data is not defined. Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n))~~ +~~START~~ +char +1 + +~~END~~ -- taking suggestion from above error, added explicit CAST and CONVERT diff --git a/test/JDBC/expected/BABEL-2999-vu-cleanup.out b/test/JDBC/expected/BABEL-2999-vu-cleanup.out new file mode 100644 index 0000000000..4b79d8c4f6 --- /dev/null +++ b/test/JDBC/expected/BABEL-2999-vu-cleanup.out @@ -0,0 +1,29 @@ +drop table if exists t2_BABEL2999; +GO + +drop table t1_BABEL2999; +GO + +drop table t3_BABEL2999; +GO + +drop table t3_BABEL2999_2; +GO + +drop procedure p1_BABEL2999; +GO + +drop procedure p2_BABEL2999 +GO + +drop procedure p3_BABEL2999 +GO + +drop table t4_BABEL2999; +GO + +drop table t5_BABEL2999; +GO + +drop table t6_BABEL2999 +GO diff --git a/test/JDBC/expected/BABEL-2999-vu-prepare.out b/test/JDBC/expected/BABEL-2999-vu-prepare.out new file mode 100644 index 0000000000..7d9b0bda16 --- /dev/null +++ b/test/JDBC/expected/BABEL-2999-vu-prepare.out @@ -0,0 +1,32 @@ +drop table if exists t1_BABEL2999; +GO + +create table t1_BABEL2999(b varchar(10)); +GO + +create table t2_BABEL2999(b int); +GO + +create table t3_BABEL2999(b varchar); +GO + +create procedure p1_BABEL2999 as select 'abc'; +GO + +create procedure p2_BABEL2999 as select 555; +GO + +create table t3_BABEL2999_2(a int, b datetime, c varchar(20)) +GO + +create procedure p3_BABEL2999 as select '123', 123, 123; +GO + +create table t4_BABEL2999( a binary(30), b varbinary(30), c varchar(30), d datetime, e smalldatetime) +GO + +create table t5_BABEL2999( a decimal, b numeric) +GO + +create table t6_BABEL2999( a int, b tinyint, c smallint) +GO diff --git a/test/JDBC/expected/BABEL-2999-vu-verify.out b/test/JDBC/expected/BABEL-2999-vu-verify.out new file mode 100644 index 0000000000..8d6ceb3d3e --- /dev/null +++ b/test/JDBC/expected/BABEL-2999-vu-verify.out @@ -0,0 +1,227 @@ +insert into t1_BABEL2999 exec('Select ''5'''); +GO +~~ROW COUNT: 1~~ + + +insert into t1_BABEL2999 exec('Select 5'); +GO +~~ROW COUNT: 1~~ + + +insert into t1_BABEL2999 exec('Select ''5'''); +GO +~~ROW COUNT: 1~~ + + +insert into t1_BABEL2999 exec('Select ''hello'''); +GO +~~ROW COUNT: 1~~ + + +insert into t1_BABEL2999 exec('SELECT ''helloworld'''); +GO +~~ROW COUNT: 1~~ + + +insert into t1_BABEL2999 exec('SELECT ''helloworldhello'''); +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character varying(10))~~ + + +select b from t1_BABEL2999 order by b; +GO +~~START~~ +varchar +5 +5 +5 +hello +helloworld +~~END~~ + + +insert into t2_BABEL2999 exec('Select ''5'''); -- varchar to int +GO +~~ROW COUNT: 1~~ + + +insert into t2_BABEL2999 exec('Select 5'); -- int to int +GO +~~ROW COUNT: 1~~ + + +insert into t2_BABEL2999 SELECT '5'; +GO +~~ROW COUNT: 1~~ + + +select b from t2_BABEL2999 order by b; +GO +~~START~~ +int +5 +5 +5 +~~END~~ + + +insert into t3_BABEL2999 exec('Select ''5'''); +GO +~~ROW COUNT: 1~~ + + +insert into t3_BABEL2999 exec('Select 5'); +GO +~~ROW COUNT: 1~~ + + +insert into t3_BABEL2999 exec('Select ''5'''); +GO +~~ROW COUNT: 1~~ + + +select b from t3_BABEL2999 order by b; +GO +~~START~~ +varchar +5 +5 +5 +~~END~~ + + +delete from t1_BABEL2999 +GO +~~ROW COUNT: 5~~ + + +insert into t1_BABEL2999 exec p1_BABEL2999; +GO +~~ROW COUNT: 1~~ + + +insert into t1_BABEL2999 exec('exec p1_BABEL2999'); +GO +~~ROW COUNT: 1~~ + + +select * from t1_BABEL2999; +GO +~~START~~ +varchar +abc +abc +~~END~~ + + +insert t3_BABEL2999_2 exec('select ''123'', 123, 123'); +GO +~~ROW COUNT: 1~~ + + +insert into t3_BABEL2999_2 exec p3_BABEL2999 +GO +~~ROW COUNT: 1~~ + + +insert into t3_BABEL2999_2 select '123', 123, 123 +GO +~~ROW COUNT: 1~~ + + +select * from t3_BABEL2999_2; +GO +~~START~~ +int#!#datetime#!#varchar +123#!#1900-05-04 00:00:00.0#!#123 +123#!#1900-05-04 00:00:00.0#!#123 +123#!#1900-05-04 00:00:00.0#!#123 +~~END~~ + + +insert into t3_BABEL2999_2 exec('select ''123'''); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: structure of query does not match function result type)~~ + + +insert into t3_BABEL2999_2 exec('select 123, 123'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: structure of query does not match function result type)~~ + + +insert into t4_BABEL2999 exec('select 123, 123, 123, 123, 123') +GO +~~ROW COUNT: 1~~ + + +insert into t4_BABEL2999 exec('select cast(123 as binary), cast(123 as varbinary), 123, cast(123 as datetime), cast(123 as smalldatetime)') +GO +~~ROW COUNT: 1~~ + + +insert into t4_BABEL2999 select 123, 123, 123, 123, 123 +GO +~~ROW COUNT: 1~~ + + +insert into t4_BABEL2999 exec('select ''123'', ''123'', ''123'', ''123'', ''123'''); +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.)~~ + + +select * from t4_BABEL2999 +GO +~~START~~ +binary#!#varbinary#!#varchar#!#datetime#!#smalldatetime +00000000000000000000000000000000000000000000000000000000007B#!#0000007B#!#123#!#1900-05-04 00:00:00.0#!#1900-05-04 00:00:00.0 +00000000000000000000000000000000000000000000000000000000007B#!#0000007B#!#123#!#1900-05-04 00:00:00.0#!#1900-05-04 00:00:00.0 +00000000000000000000000000000000000000000000000000000000007B#!#0000007B#!#123#!#1900-05-04 00:00:00.0#!#1900-05-04 00:00:00.0 +~~END~~ + + +insert into t5_BABEL2999 exec('select ''1.234'', ''33.33'''); +GO +~~ROW COUNT: 1~~ + + +select * from t5_BABEL2999 +GO +~~START~~ +numeric#!#numeric +1#!#33 +~~END~~ + + +insert into t6_BABEL2999 exec('select 1,2,3') +GO +~~ROW COUNT: 1~~ + + +insert into t6_BABEL2999 exec('select ''1'',''2'',''3''') +GO +~~ROW COUNT: 1~~ + + +insert into t6_BABEL2999 exec('select c,b,a from t6_BABEL2999') +GO +~~ROW COUNT: 2~~ + + +select * from t6_BABEL2999 +GO +~~START~~ +int#!#tinyint#!#smallint +1#!#2#!#3 +1#!#2#!#3 +3#!#2#!#1 +3#!#2#!#1 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-3066-vu-cleanup.out b/test/JDBC/expected/BABEL-3066-vu-cleanup.out new file mode 100644 index 0000000000..8a7a702ca2 --- /dev/null +++ b/test/JDBC/expected/BABEL-3066-vu-cleanup.out @@ -0,0 +1,5 @@ +DROP TABLE babel_3066_vu_prepare_t1; +GO + +DROP TABLE babel_3066_vu_prepare_t2; +GO diff --git a/test/JDBC/expected/BABEL-3066-vu-prepare.out b/test/JDBC/expected/BABEL-3066-vu-prepare.out new file mode 100644 index 0000000000..e7256d35a7 --- /dev/null +++ b/test/JDBC/expected/BABEL-3066-vu-prepare.out @@ -0,0 +1,5 @@ +CREATE TABLE babel_3066_vu_prepare_t1(col1 real); +GO + +CREATE TABLE babel_3066_vu_prepare_t2(col1 numeric(30, 3)); +GO diff --git a/test/JDBC/expected/BABEL-3066-vu-verify.out b/test/JDBC/expected/BABEL-3066-vu-verify.out new file mode 100644 index 0000000000..4286cc7fe9 --- /dev/null +++ b/test/JDBC/expected/BABEL-3066-vu-verify.out @@ -0,0 +1,600 @@ +SELECT CAST(123456.25 AS real) AS value_as_real, CAST(CAST(123456.25 AS real) AS decimal(30,2)) AS value_casted_to_decimal_30_2; +GO +~~START~~ +real#!#numeric +123456.25#!#123456.25 +~~END~~ + + +select cast(cast(123457.145637867 as real) as numeric (30, 20)); +GO +~~START~~ +numeric +123457.14843750000000000000 +~~END~~ + + +select cast((cast(123456.00 as real)) as numeric(30,2)); +GO +~~START~~ +numeric +123456.00 +~~END~~ + + +SELECT CAST(123456.25 AS real) AS value_as_real, CAST(CAST(123456.25 AS real) AS decimal(30,2)) AS real_casted_to_decimal_30_2; +GO +~~START~~ +real#!#numeric +123456.25#!#123456.25 +~~END~~ + + +select CAST(CAST(123457.145637867 as real) as numeric (30, 20)); +GO +~~START~~ +numeric +123457.14843750000000000000 +~~END~~ + + +select CAST((CAST(123456.00 as real)) as numeric(30,2)); +GO +~~START~~ +numeric +123456.00 +~~END~~ + + + +select CAST(CAST(123457.145637867 as real) as numeric (30, 0)); +GO +~~START~~ +numeric +123457 +~~END~~ + + + +select CAST((CAST(123456.00 as real)) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + + +-- should throw error +select CAST(CAST(123457.145637867 as real) as numeric (30, 38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The scale 38 for 'numeric' datatype must be within the range 0 to precision 30)~~ + + +-- Boundary real values +SELECT CAST(CAST(3e+38 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(3e+38 as real) as numeric(38,0)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(3e+38 as real) as numeric(30,10)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + + +SELECT CAST(CAST(-3e+38 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(-3e+38 as real) as numeric(38,0)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(-3e+38 as real) as numeric(30,10)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(3e-38 as real) as numeric(38,38)); +GO +~~START~~ +numeric +3E-38 +~~END~~ + + +SELECT CAST(CAST(3e-38 as real) as numeric(38,0)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST(CAST(3e-38 as real) as numeric(30,10)); +GO +~~START~~ +numeric +0E-10 +~~END~~ + + +SELECT CAST(CAST(-3e-38 as real) as numeric(38,38)); +GO +~~START~~ +numeric +-3E-38 +~~END~~ + + +SELECT CAST(CAST(-3e-38 as real) as numeric(38,0)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST(CAST(-3e-38 as real) as numeric(30,10)); +GO +~~START~~ +numeric +0E-10 +~~END~~ + + +-- table insertion +INSERT INTO babel_3066_vu_prepare_t1 VALUES (122.34562), (735412.97354), (-467822.56378), (-456.24516), (1234.465), ('inf'), ('-inf'), ('nan'); +GO +~~ROW COUNT: 8~~ + +INSERT INTO babel_3066_vu_prepare_t1 VALUES (123456789123456789123456789123456789.123456789); +GO +~~ROW COUNT: 1~~ + + +SELECT CAST(col1 as numeric(30,2)) as value_casted_to_decimal_30_2 from babel_3066_vu_prepare_t1; +GO +~~START~~ +numeric +122.35 +735413.00 +-467822.56 +-456.25 +1234.46 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + +SELECT CAST(col1 as numeric(30,20)) as value_casted_to_decimal_30_20 from babel_3066_vu_prepare_t1; +GO +~~START~~ +numeric +122.34561920166015625000 +735413.00000000000000000000 +-467822.56250000000000000000 +-456.24514770507812500000 +1234.46496582031250000000 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + +SELECT CAST(col1 as numeric(30,4)) as value_casted_to_decimal_30_4 from babel_3066_vu_prepare_t1; +GO +~~START~~ +numeric +122.3456 +735413.0000 +-467822.5625 +-456.2451 +1234.4650 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + +SELECT CAST(col1 as numeric(38,38)) as value_casted_to_decimal_38_38 from babel_3066_vu_prepare_t1; +GO +~~START~~ +numeric +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +INSERT INTO babel_3066_vu_prepare_t2 values (CAST(1234.156 as real)), (CAST(-3256.55 as real)), (CAST(1234.6513 as real)), (CAST(1324567.45267781 as real)), (CAST(12.2 as real)), (CAST(122.34562 as real)), (CAST(735412.97354 as real)); +GO +~~ROW COUNT: 7~~ + + +INSERT INTO babel_3066_vu_prepare_t2 values (123456789123456789123456789123456789.123456789); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT col1 from babel_3066_vu_prepare_t2; +GO +~~START~~ +numeric +1234.156 +-3256.550 +1234.651 +1324567.500 +12.200 +122.346 +735413.000 +~~END~~ + + +select CAST(CAST(col1 AS real) AS decimal(30,2)) from babel_3066_vu_prepare_t2; +GO +~~START~~ +numeric +1234.16 +-3256.55 +1234.65 +1324567.50 +12.20 +122.35 +735413.00 +~~END~~ + + +SELECT babel_3066_vu_prepare_t1.col1, babel_3066_vu_prepare_t2.col1 +FROM babel_3066_vu_prepare_t1 JOIN babel_3066_vu_prepare_t2 +ON CAST (babel_3066_vu_prepare_t1.col1 as real) = CAST(CAST(babel_3066_vu_prepare_t2.col1 AS real) AS decimal(30,2)); +GO +~~START~~ +real#!#numeric +735413.0#!#735413.000 +~~END~~ + + + +-- Directly cast to numeric +SELECT CAST(.12345678912345678912345678912345678912 as numeric(38,38)); +GO +~~START~~ +numeric +0.12345678912345678912345678912345678912 +~~END~~ + + +SELECT CAST(123456.789012 as numeric(38,0)); +GO +~~START~~ +numeric +123457 +~~END~~ + + +SELECT CAST(123456.489012 as numeric(38,0)); +GO +~~START~~ +numeric +123456 +~~END~~ + + +SELECT CAST(123456.789012 as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(.12345678 as numeric(1,0)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST(.12345678 as numeric(1,1)); +GO +~~START~~ +numeric +0.1 +~~END~~ + + + +-- should throw error +SELECT CAST(123.1234567891234567891234567891234567 as numeric(38,39)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The scale 39 for 'numeric' datatype must be within the range 0 to precision 38)~~ + + +SELECT CAST(123.1234567891234567891234567891234567 as numeric(39,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The size (39) given to the type 'numeric' exceeds the maximum allowed (38))~~ + + +SELECT CAST(.12345678 as numeric(0,1)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Specified column precision 0 for 'numeric' datatype must be within the range 1 to maximum precision(38))~~ + + + +-- Cast expressions value with diff operators to numeric +SELECT CAST((CAST(123.45628 as real) + cast(36791.45789926 as real)) as numeric(38, 0)); +GO +~~START~~ +numeric +36915 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) + cast(36791.45789926 as real)) as numeric(38, 38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST((CAST(123.45628 as real) + cast(36791.45789926 as real)) as numeric(30, 10)); +GO +~~START~~ +numeric +36914.9140625000 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) - cast(36791.45789926 as real)) as numeric(38, 0)); +GO +~~START~~ +numeric +-36668 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) - cast(36791.45789926 as real)) as numeric(38, 38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST((CAST(123.45628 as real) - cast(36791.45789926 as real)) as numeric(30, 10)); +GO +~~START~~ +numeric +-36668.0000000000 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) * cast(36791.45789926 as real)) as numeric(38, 0)); +GO +~~START~~ +numeric +4542137 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) * cast(36791.45789926 as real)) as numeric(38, 38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST((CAST(123.45628 as real) * cast(36791.45789926 as real)) as numeric(30, 10)); +GO +~~START~~ +numeric +4542136.5000000000 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) / cast(36791.45789926 as real)) as numeric(38, 0)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) / cast(36791.45789926 as real)) as numeric(38, 38)); +GO +~~START~~ +numeric +0.00335556920617818832397460937500000000 +~~END~~ + + +SELECT CAST((CAST(123.45628 as real) / cast(36791.45789926 as real)) as numeric(30, 10)); +GO +~~START~~ +numeric +0.0033555692 +~~END~~ + + +-- Expression over casted value -> cast(x) + cast(y) +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) + CAST(CAST(12465781.4679213254 as real) as numeric(38,0)); +GO +~~START~~ +numeric +24931562 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) + CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,38)) + CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) + CAST(CAST(12465781.4679213254 as real) as numeric(38,15)); +GO +~~START~~ +numeric +24931562.000000000000000 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) + CAST(CAST(12465781.4679213254 as real) as numeric(38,10)); +GO +~~START~~ +numeric +24931562.0000000000 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) - CAST(CAST(12465781.4679213254 as real) as numeric(38,0)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) - CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,38)) - CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) - CAST(CAST(12465781.4679213254 as real) as numeric(38,15)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) - CAST(CAST(12465781.4679213254 as real) as numeric(38,10)); +GO +~~START~~ +numeric +0 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) * CAST(CAST(12465781.4679213254 as real) as numeric(38,0)); +GO +~~START~~ +numeric +155395695939961 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) * CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,38)) * CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) * CAST(CAST(12465781.4679213254 as real) as numeric(38,15)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Arithmetic overflow error for data type numeric.)~~ + + +SELECT CAST(CAST(CAST(CAST(12465781.46792 as real) as numeric(38,10)) * CAST(CAST(12465781.4679213254 as real) as numeric(38,15)) as real) as numeric(38,6)); +GO +~~START~~ +numeric +155395691642880.000000 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) * CAST(CAST(12465781.4679213254 as real) as numeric(38,10)); +GO +~~START~~ +numeric +155395695939961.00000000000000000000 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) / CAST(CAST(12465781.4679213254 as real) as numeric(38,0)); +GO +~~START~~ +numeric +1.00000000000000000000 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,0)) / CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,38)) / CAST(CAST(12465781.4679213254 as real) as numeric(38,38)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: numeric field overflow)~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) / CAST(CAST(12465781.4679213254 as real) as numeric(38,15)); +GO +~~START~~ +numeric +1.00000000000000000000 +~~END~~ + + +SELECT CAST(CAST(12465781.46792 as real) as numeric(38,10)) / CAST(CAST(12465781.4679213254 as real) as numeric(38,10)); +GO +~~START~~ +numeric +1.00000000000000000000 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-3117-vu-verify.out b/test/JDBC/expected/BABEL-3117-vu-verify.out index 7a41f636ec..dd98aee04a 100644 --- a/test/JDBC/expected/BABEL-3117-vu-verify.out +++ b/test/JDBC/expected/BABEL-3117-vu-verify.out @@ -165,6 +165,10 @@ GO USE master GO +-- reset the login password +ALTER LOGIN BABEL_3117_login WITH PASSWORD = '123' +GO + -- tsql user=BABEL_3117_login password=123 -- Test if user default schema is not dbo schema USE master diff --git a/test/JDBC/expected/BABEL-3166-vu-prepare.out b/test/JDBC/expected/BABEL-3166-vu-prepare.out index e04a7fd77e..90e274de21 100644 --- a/test/JDBC/expected/BABEL-3166-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3166-vu-prepare.out @@ -1,9 +1,3 @@ -CREATE DATABASE db_babel_3166; -go - -USE db_babel_3166; -go - -- function CREATE FUNCTION babel_3166_func(@a numeric, @b varchar, @c varchar(max), @d varchar(8), @e binary(6)) RETURNS varbinary(8) AS BEGIN RETURN @e END; diff --git a/test/JDBC/expected/BABEL-3166-vu-verify.out b/test/JDBC/expected/BABEL-3166-vu-verify.out index a97752db88..9a44eeb924 100644 --- a/test/JDBC/expected/BABEL-3166-vu-verify.out +++ b/test/JDBC/expected/BABEL-3166-vu-verify.out @@ -1,6 +1,3 @@ -USE db_babel_3166; -go - -- Look at function's probin for typmod information SELECT proname, probin FROM pg_proc WHERE proname = 'babel_3166_func'; go @@ -39,9 +36,3 @@ binary DROP PROCEDURE babel_3166_proc; go - -USE master; -go - -DROP DATABASE db_babel_3166; -go diff --git a/test/JDBC/expected/BABEL-3168-vu-cleanup.out b/test/JDBC/expected/BABEL-3168-vu-cleanup.out new file mode 100644 index 0000000000..f3d2f62ae1 --- /dev/null +++ b/test/JDBC/expected/BABEL-3168-vu-cleanup.out @@ -0,0 +1,14 @@ +drop procedure p3168 +go + +drop procedure p3168_2 +go + +drop procedure p3168_3 +go + +drop procedure p3168_4 +go + +drop type typ3168 +go diff --git a/test/JDBC/expected/BABEL-3168-vu-prepare.out b/test/JDBC/expected/BABEL-3168-vu-prepare.out new file mode 100644 index 0000000000..091918819a --- /dev/null +++ b/test/JDBC/expected/BABEL-3168-vu-prepare.out @@ -0,0 +1,25 @@ +create procedure p3168 as begin +create table #t (id int identity(1,1)) +end +go + +create procedure p3168_2 as begin +create table #t (id int identity primary key) +create index i on #t(id) +end +go + +create procedure p3168_3 as begin +create table #t (id int) +create index i on #t(id) +end +go + +create type typ3168 from int +go + +create procedure p3168_4 as begin +create table #t(id typ3168 primary key) +create index i on #t(id) +end +go diff --git a/test/JDBC/expected/BABEL-3168-vu-verify.out b/test/JDBC/expected/BABEL-3168-vu-verify.out new file mode 100644 index 0000000000..8f4173cdd8 --- /dev/null +++ b/test/JDBC/expected/BABEL-3168-vu-verify.out @@ -0,0 +1,12 @@ +exec p3168 +go + +exec p3168_2 +go + +exec p3168_3 +go + +exec p3168_4 +go + diff --git a/test/JDBC/expected/BABEL-3192-vu-prepare.out b/test/JDBC/expected/BABEL-3192-vu-prepare.out index 43409d3d76..82fe7e8b7d 100644 --- a/test/JDBC/expected/BABEL-3192-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3192-vu-prepare.out @@ -1,9 +1,3 @@ -CREATE DATABASE db_babel_3192; -go - -USE db_babel_3192; -go - -- T-SQL table-type CREATE TYPE babel_3192_type AS TABLE (a int, b int); go diff --git a/test/JDBC/expected/BABEL-3192-vu-verify.out b/test/JDBC/expected/BABEL-3192-vu-verify.out index a2418ac98e..014a1e06f7 100644 --- a/test/JDBC/expected/BABEL-3192-vu-verify.out +++ b/test/JDBC/expected/BABEL-3192-vu-verify.out @@ -1,6 +1,3 @@ -USE db_babel_3192; -go - -- T-SQL table-type DECLARE @tablevar babel_3192_type; INSERT INTO @tablevar(a,b) VALUES(1,1); @@ -71,9 +68,3 @@ go DROP TYPE babel_3192_type; go - -USE master; -go - -DROP DATABASE db_babel_3192; -go diff --git a/test/JDBC/expected/BABEL-3201-vu-cleanup.out b/test/JDBC/expected/BABEL-3201-vu-cleanup.out new file mode 100644 index 0000000000..455056962a --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-cleanup.out @@ -0,0 +1,59 @@ +DROP TABLE babel_3201_t_int; +GO + +DROP TABLE babel_dbcc_check_t1; +GO + +DROP TABLE [babel_dbcc_check_t2 .with .dot_an_spaces]; +GO + +DROP TABLE [babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces"; +GO + +DROP SCHEMA [babel_dbcc_check_schema .with .dot_and_spaces] +GO + +DROP TABLE babel_3201_t_tinyint; +GO + +DROP TABLE babel_3201_t_smallint; +GO + +DROP TABLE babel_3201_t_bigint; +GO + +DROP TABLE babel_3201_t_numeric; +GO + +DROP TABLE babel_3201_t_decimal; +GO + +DROP TABLE babel_3201_t1; +GO + +DROP TABLE babel_3201_t2; +GO + +DROP TABLE babel_3201_sch1.babel_3201_t2; +GO + +DROP TABLE babel_3201_test_locks; +GO + +DROP PROCEDURE babel_3201_proc1; +GO + +DROP PROCEDURE babel_3201_proc2; +GO + +DROP LOGIN babel_3201_log1; +GO + +DROP LOGIN babel_3201_test_locks; +GO + +DROP SCHEMA babel_3201_sch1; +GO + +DROP DATABASE babel_3201_db1; +GO diff --git a/test/JDBC/expected/BABEL-3201-vu-prepare.out b/test/JDBC/expected/BABEL-3201-vu-prepare.out new file mode 100644 index 0000000000..4bef6e6006 --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-prepare.out @@ -0,0 +1,163 @@ +CREATE SCHEMA babel_3201_sch1; +GO + +CREATE TABLE babel_3201_sch1.babel_3201_t2(a varchar(20), b int identity); +GO + +CREATE TABLE babel_3201_t_int( a int identity, b int); +GO + +CREATE TABLE babel_dbcc_check_t1 (a int identity, b int); +GO + +CREATE TABLE [babel_dbcc_check_t2 .with .dot_an_spaces] (a int identity, b int); +GO + +CREATE SCHEMA [babel_dbcc_check_schema .with .dot_and_spaces] +GO + +CREATE TABLE [babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces" (a int identity, b int); +GO + +CREATE TABLE babel_3201_t_tinyint( a tinyint identity(5,1), b int); +GO + +CREATE TABLE babel_3201_t_smallint( a smallint identity(10,10), b int); +GO + +CREATE TABLE babel_3201_t_bigint( a bigint identity(3,3), b int); +GO + +CREATE TABLE babel_3201_t_numeric( a numeric identity(4,2), b int); +GO + +CREATE TABLE babel_3201_t_decimal( a decimal identity(7,3), b int); +GO + +CREATE TABLE babel_3201_t1( a int identity, b int); +GO + +CREATE TABLE babel_3201_t2( a int, b int); +GO + +CREATE TABLE babel_3201_test_locks (a int identity, b int); +GO + +INSERT INTO babel_3201_test_locks VALUES (10); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_sch1.babel_3201_t2 VALUES ('string 1'); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_tinyint VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_tinyint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_tinyint VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_smallint VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_smallint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_smallint VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_int VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_int VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_int VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_bigint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_bigint VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_numeric VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_numeric VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_numeric VALUES (7); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_decimal VALUES (5); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_decimal VALUES (6); +GO +~~ROW COUNT: 1~~ + + +INSERT INTO babel_3201_t_decimal VALUES (7); +GO +~~ROW COUNT: 1~~ + + +CREATE PROCEDURE babel_3201_proc1 +AS +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 30) +GO + +CREATE PROCEDURE babel_3201_proc2 +AS +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 257) +GO + +CREATE LOGIN babel_3201_log1 WITH PASSWORD='12345678'; +GO + +CREATE LOGIN babel_3201_test_locks WITH PASSWORD='123456'; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER babel_3201_test_locks +GO diff --git a/test/JDBC/expected/BABEL-3201-vu-verify.out b/test/JDBC/expected/BABEL-3201-vu-verify.out new file mode 100644 index 0000000000..75f5e7b611 --- /dev/null +++ b/test/JDBC/expected/BABEL-3201-vu-verify.out @@ -0,0 +1,819 @@ +DBCC CHECKIDENT(babel_3201_t_int, NORESEED); +GO + +-- test with mixed case in table name +DBCC CHECKIDENT(BABEL_3201_t_iNt, NORESEED); +GO +DBCC CHECKIDENT(BABEL_3201_T_INT, NORESEED); +GO + +-- test with table in quotes (+mixed cases) +DBCC CHECKIDENT('babel_3201_t_int', NORESEED); +GO +DBCC CHECKIDENT('baBEl_3201_T_inT', NORESEED); +GO + +-- test with table in brackets (+mixed case) +DBCC CHECKIDENT([babel_3201_t_int], NORESEED); +GO +DBCC CHECKIDENT([baBEL_3201_t_InT], NORESEED); +GO + +-- test with table in brackets with quotes (+mixed case) +DBCC CHECKIDENT('[babel_3201_t_int]', NORESEED); +GO +DBCC CHECKIDENT('[BABEL_3201_t_int]', NORESEED); +GO + +-- test when trailing space - should work +DBCC CHECKIDENT('babel_3201_t_int ', NORESEED); +GO +DBCC CHECKIDENT('babel_3201_T_INT ', NORESEED); +GO + +-- test when leading space - should throw error +DBCC CHECKIDENT(' babel_3201_t_int ', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation " babel_3201_t_int" does not exist)~~ + + +-- test when table name is empty in quotes +DBCC CHECKIDENT('', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Parameter 1 is incorrect for this DBCC statement)~~ + + +-- same as DBCC CHECKIDENT(, RESEED), identity value is not changed +-- if current identity value for a table is less than the maximum identity value +-- stored in the identity column +DBCC CHECKIDENT(babel_3201_t_int); +GO + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED); +GO + +INSERT INTO babel_3201_t_int VALUES (8); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_int; +GO +~~START~~ +int#!#int +1#!#5 +2#!#6 +3#!#7 +4#!#8 +~~END~~ + + +DBCC CHECKIDENT('babel_3201_sch1.babel_3201_t2'); +GO + +-- Set identity value to 5 which is less than the maximum value(which is 9) of the identity +-- column, using RESEED option in this case should will reset the identity value +-- to maximum value of the identity column. Value inserted in next insert will +-- be (max_identity_col_value + increament). +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 5); +GO +INSERT INTO babel_3201_t_bigint VALUES (8); +GO +~~ROW COUNT: 1~~ + +SELECT * from babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +3#!#5 +6#!#6 +9#!#6 +8#!#8 +~~END~~ + + +-- This will reset the current identity value(currently 8) to the maximum value of the identity column (currently 9) +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED); +GO +INSERT INTO babel_3201_t_bigint VALUES (9); +GO +~~ROW COUNT: 1~~ + +SELECT * from babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +3#!#5 +6#!#6 +9#!#6 +8#!#8 +12#!#9 +~~END~~ + + +-- no rows have been inserted in the table; both current identity value current +-- column value should be NULL (TO-DO) +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +SELECT * FROM babel_3201_t1; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value 'NULL', current column value 'NULL'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +~~END~~ + + +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, RESEED); +SELECT * FROM babel_3201_t1; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value 'NULL', current column value 'NULL'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +~~END~~ + + +-- current identity value should be NULL (TO-DO), identity value inserted in +-- next INSERT operation should be new_reseed_value. +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, RESEED, 5); +INSERT INTO babel_3201_t1 VALUES (50); +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value 'NULL'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + + +BEGIN TRAN; +DBCC CHECKIDENT(babel_3201_t1, NORESEED); +select * from babel_3201_t1; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '5', current column value '5'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +5#!#50 +~~END~~ + + +-- Remove all rows in table using TRUNCATE TABLE, Identity value will become NULL +-- next insert operation should be default identity value if no new_reseed_value is provided. +TRUNCATE TABLE babel_3201_t_int; +GO +dbcc checkident(babel_3201_t_int, NORESEED); +GO +INSERT INTO babel_3201_t_int values(15); +GO +~~ROW COUNT: 1~~ + + +select * from babel_3201_t_int; +-- Remove all rows in table using TRUNCATE TABLE, identity value inserted in +-- next INSERT operation should be new_reseed_value. +TRUNCATE TABLE babel_3201_t_int; +GO +~~START~~ +int#!#int +1#!#15 +~~END~~ + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, 10); +GO +INSERT INTO babel_3201_t_int VALUES (5); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_int; +GO +~~START~~ +int#!#int +10#!#5 +~~END~~ + + + +-- Remove all rows in table using DELETE TABLE, identity value inserted in next +-- INSERT operation should be (new_reseed_value + increment). +DELETE FROM babel_3201_t_bigint; +GO +~~ROW COUNT: 5~~ + +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 10); +GO +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +13#!#5 +~~END~~ + + +-- Remove all rows in table using DELETE TABLE current identity will not become default identity value, +-- identity value inserted in next operation should use (default identity value + increament) if no new_reseed_value is provided. +DELETE FROM babel_3201_t_bigint; +GO +~~ROW COUNT: 1~~ + +dbcc checkident(babel_3201_t_bigint, NORESEED); +GO +INSERT INTO babel_3201_t_bigint VALUES (5); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +16#!#5 +~~END~~ + + +-- If some rows are present already in the table, identity value inserted in next +-- INSERT operation should be (new_reseed_value + increament) +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 27); +GO +INSERT INTO babel_3201_t_bigint VALUES (32); +GO +~~ROW COUNT: 1~~ + +SELECT * FROM babel_3201_t_bigint; +GO +~~START~~ +bigint#!#int +16#!#5 +30#!#32 +~~END~~ + + +-- Incorrect DBCC command option +DBCC CHECKIDENT(babel_3201_t1) WITH NO_INFO; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NO_INFO' is not a recognized option)~~ + + +-- Invalid parameter 1 +DBCC CHECKIDENT(5); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '5' at line 2 and character position 16)~~ + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, ) WITH NO_INFOMSGS; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ')' at line 1 and character position 42)~~ + + +-- Invalid keyword +DBCC CHECKIDENT(babel_3201_t1, RESEE); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'RESEE' at line 2 and character position 31)~~ + + +-- Invalid datatype +DBCC CHECKIDENT(babel_3201_t1, RESEED, 1313abc); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'abc' at line 2 and character position 43)~~ + + +-- Unsupported DBCC command +DBCC CHECKTABLE(babel_3201_t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: DBCC CHECKTABLE is not currently supported in Babelfish)~~ + +DBCC checktable(babel_3201_t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: DBCC CHECKTABLE is not currently supported in Babelfish)~~ + + +-- Invalid DBCC command +DBCC FAKE_COMMAND(t1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Incorrect DBCC statement. Check the documentation for the correct DBCC syntax and options.)~~ + + +-- Database undefined +DBCC CHECKIDENT('fake_db.dbo.babel_3201_t1', NORESEED); +GO +~~ERROR (Code: 911)~~ + +~~ERROR (Message: database "fake_db" does not exist)~~ + + +-- Schema undefined +DBCC CHECKIDENT('fake_schema.babel_3201_t1', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: schema "master_fake_schema" does not exist)~~ + + +-- Table undefined +DBCC CHECKIDENT(fake_babel_3201_t1, RESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "fake_babel_3201_t1" does not exist)~~ + + +-- Table does not have identity column +DBCC CHECKIDENT(babel_3201_t2, RESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'master_dbo.babel_3201_t2' does not contain an identity column.)~~ + + +-- new_reseed_value as expression is not allowed +DBCC CHECKIDENT(babel_3201_t2, RESEED, 4+5); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '+' at line 2 and character position 40)~~ + + +-- new_reseed_value is out of tinyint datatype range +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, 256); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 256 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + + +DBCC CHECKIDENT(babel_3201_t_tinyint, RESEED, -1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -1 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + + +-- new_reseed_value is out of smallint datatype range +DBCC CHECKIDENT(babel_3201_t_smallint, RESEED, 32768); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 32768 is out of bounds for sequence "babel_3201_t_smallint_a_seq" (10..32767))~~ + + +DBCC CHECKIDENT(babel_3201_t_smallint, RESEED, -32769); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -32769 is out of bounds for sequence "babel_3201_t_smallint_a_seq" (10..32767))~~ + + + +-- new_reseed_value is out of int datatype range +DBCC CHECKIDENT(babel_3201_t_int, RESEED, 2147483648); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 2147483648 is out of bounds for sequence "babel_3201_t_int_a_seq" (1..2147483647))~~ + + +DBCC CHECKIDENT(babel_3201_t_int, RESEED, -2147483649); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -2147483649 is out of bounds for sequence "babel_3201_t_int_a_seq" (1..2147483647))~~ + + +-- new_reseed_value is out of bigint datatype range +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, 9223372036854775808); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value "9223372036854775808" is out of range for type bigint)~~ + + +DBCC CHECKIDENT(babel_3201_t_bigint, RESEED, -9223372036854775809); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value "-9223372036854775809" is out of range for type bigint)~~ + + +-- numeric/decimal datatypes are internally converted to bigint, so allowed +-- range is same as that of bigint +DBCC CHECKIDENT(babel_3201_t_numeric, RESEED, 9223372036854775808); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: value "9223372036854775808" is out of range for type bigint)~~ + + +-- When new_reseed_value is a float value, only value before the decimal is used +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 15.65); +GO + +-- When reseed_value is negative and zero, bbf currently does not support reseed to negative/zero value +dbcc checkident(babel_3201_t_decimal, reseed, -10) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value -10 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, 0) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 0 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, .123) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 0 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, -.123) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 0 is out of bounds for sequence "babel_3201_t_decimal_a_seq" (7..9223372036854775807))~~ + +dbcc checkident(babel_3201_t_decimal, reseed, .) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '.' at line 1 and character position 46)~~ + +dbcc checkident(babel_3201_t_decimal, reseed, -) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ')' at line 1 and character position 47)~~ + +dbcc checkident(babel_3201_t_decimal, reseed, .-); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '.' at line 1 and character position 46)~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +~~END~~ + + +begin tran; +DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 10); +INSERT INTO babel_3201_t_decimal VALUES (9); +commit; +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '15'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +13#!#9 +~~END~~ + + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 133ac); + INSERT INTO babel_3201_t_decimal VALUES (10); +COMMIT; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'ac' at line 2 and character position 53)~~ + + +SELECT * FROM babel_3201_t_decimal; +GO +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +13#!#9 +~~END~~ + + +BEGIN TRAN; + DBCC CHECKIDENT(babel_3201_t_decimal, RESEED, 20); + INSERT INTO babel_3201_t_decimal VALUES (11); +ROLLBACK; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '13'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + + +-- Check current_identity value after tran rollback +-- babelfish does not support rolling-back dbcc changes after transection rollback. +-- Current identity value will be = reseed_value inside the rollbacked transection + increament = 20+3=23 +BEGIN TRAN; +dbcc checkident(babel_3201_t_decimal, noreseed); +SELECT * FROM babel_3201_t_decimal; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '23', current column value '13'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +bigint#!#int +7#!#5 +10#!#6 +13#!#7 +13#!#9 +~~END~~ + + +EXEC babel_3201_proc1; +GO + +INSERT INTO babel_3201_t_tinyint VALUES (10); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_3201_t_tinyint; +GO +~~START~~ +smallint#!#int +5#!#5 +6#!#6 +7#!#7 +31#!#10 +~~END~~ + + +EXEC babel_3201_proc2; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: setval: value 257 is out of bounds for sequence "babel_3201_t_tinyint_a_seq" (5..255))~~ + + +-- testing different scenarios of 3-part name +DBCC CHECKIDENT('dbo.babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('..babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('master.dbo.babel_dbcc_check_t1') +GO + +DBCC CHECKIDENT('[master]."dbo".[babel_dbcc_check_t1]') +GO + +DBCC CHECKIDENT('"master".[dbo]."babel_dbcc_check_t1"') +GO + +DBCC CHECKIDENT('master..babel_dbcc_check_t1') +GO + +-- with mixed case names of db, schema, and table. +DBCC CHECKIDENT('dbo.BABEL_DBCC_check_t1') +GO +DBCC CHECKIDENT('master.DBO.BABEL_dbcc_check_t1') +GO +DBCC CHECKIDENT('[MASTER]."dBo".[babel_dbcc_CHECK_t1]') +GO + +-- schema and object name containing spaces and dots +DBCC CHECKIDENT('[babel_dbcc_check_t2 .with .dot_an_spaces]'); +GO + +DBCC CHECKIDENT('master.."babel_dbcc_check_t2 .with .dot_an_spaces"'); +GO + +DBCC CHECKIDENT('[babel_dbcc_check_schema .with .dot_and_spaces]."babel_dbcc_check_t3 .with .dot_and_spaces"'); +GO + +-- schema and object name containing spaces and dots + mixed case +DBCC CHECKIDENT('[BABEL_DBCC_CHECK_T2 .with .dOT_AN_SPACES]'); +GO + +DBCC CHECKIDENT('MASTer.."babel_dbcc_CHECK_T2 .with .dot_an_SPACES"'); +GO + +DBCC CHECKIDENT('[babel_DBCC_CHECK_schema .with .DOT_and_spaces]."babel_dbcc_CHECK_T3 .with .dot_and_spaces"'); +GO + +-- db name longer then 63 and doing cross db call +CREATE DATABASE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +USE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +CREATE TABLE babel_3201_longer__name_db_table (a int identity, b int); +GO + +USE master; +go + +DBCC CHECKIDENT('babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij.dbo.babel_3201_longer__name_db_table', noreseed); +GO + +-- db name longer and mixed case as well. +DBCC CHECKIDENT('bAbEl_dBcC_ChEcKiDeNt_dAtAbAsE_LoNgEr_tHaN_63_0AbCdEfGiJ1AbCdEfGiJ2AbCdEfGiJ3AbCdEfGiJ4AbCdEfGiJ5AbCdEfGiJ6AbCdEfGiJ7AbCdEfGiJ8AbCdEfGhIj9aBcDeFgHiJ.dbo.babel_3201_longer__name_db_table', noreseed); +GO + +-- drop this db because of single_db mode +DROP DATABASE babel_dbcc_checkident_database_longer_than_63_0abcdefgij1abcdefgij2abcdefgij3abcdefgij4abcdefgij5abcdefgij6abcdefgij7abcdefgij8abcdefghij9abcdefghij +GO + +-- create database to test cross db behavior. +CREATE DATABASE babel_3201_db1; +GO + +USE babel_3201_db1 +GO + +CREATE TABLE babel_3201_db1_database_table1(a int identity, b int); +GO + +CREATE USER babel_3201_db1_log1_usr1 FOR LOGIN babel_3201_log1 +GO + +-- tsql user=babel_3201_log1 password=12345678 +-- Should throw - must be owner of schema dbo +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of schema dbo)~~ + + +-- tsql +USE babel_3201_db1 +GO +DROP USER babel_3201_db1_log1_usr1 +GO + + +-- tsql user=babel_3201_log1 password=12345678 +-- Should throw - The server principal "babel_3201_log1" is not able to access the database "babel_3201_db1" under the current security context +DBCC CHECKIDENT('babel_3201_db1..babel_3201_db1_database_table1', NORESEED); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server principal "babel_3201_log1" is not able to access the database "babel_3201_db1" under the current security context)~~ + + +-- tsql +USE babel_3201_db1 +GO +GRANT CONNECT TO GUEST; +GO + +-- tsql user=babel_3201_log1 password=12345678 +-- Permission Check +USE babel_3201_db1; +GO + +-- should throw error - must be owner of schema master_dbo +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of schema master_dbo)~~ + + +-- tsql +USE master; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER babel_3201_log1; +GO + +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO + +-- This should work correctly +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- tsql +-- test locks in two connections transaction. +BEGIN TRAN +DBCC CHECKIDENT('babel_3201_test_locks', noreseed) +GO + + +-- tsql user=babel_3201_test_locks password=123456 +-- This reseed the identity values while the other transaction is not yet completed. +BEGIN TRAN +DBCC CHECKIDENT('babel_3201_test_locks', reseed, 101); +SELECT * FROM babel_3201_test_locks; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '1'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +1#!#10 +~~END~~ + + +-- tsql +-- This will show the changed values of ident +DBCC CHECKIDENT('babel_3201_test_locks', noreseed); +SELECT * FROM babel_3201_test_locks; +COMMIT; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Checking identity information: current identity value '101', current column value '1'. +DBCC execution completed. If DBCC printed error messages, contact your system administrator. Server SQLState: S0001)~~ + +~~START~~ +int#!#int +1#!#10 +~~END~~ + + +-- tsql +-- test with user name longer then 64 chars. +USE MASTER +GO +CREATE USER babel_3201_db1_log1_user_name_longer_then_64_char_abdhcdjddjdhskdsh FOR LOGIN babel_3201_log1 +GO + +-- tsql user=babel_3201_log1 password=12345678 +USE babel_3201_db1; +GO +CREATE SCHEMA [babel_3201_user_schema] +GO +CREATE TABLE [babel_3201_db1].[babel_3201_user_schema].[babel_3201_user_table] (a int identity, b int); +GO +-- This should work correctly +DBCC CHECKIDENT('[babel_3201_db1].[babel_3201_user_schema].[babel_3201_user_table]', NORESEED); +GO +DBCC CHECKIDENT('master.dbo.babel_3201_t_tinyint', RESEED, 10) +GO + +-- tsql +USE master; +GO +DROP USER babel_3201_db1_log1_user_name_longer_then_64_char_abdhcdjddjdhskdsh +GO diff --git a/test/JDBC/expected/BABEL-3204-vu-prepare.out b/test/JDBC/expected/BABEL-3204-vu-prepare.out index a6e599d16b..3e32819fcc 100644 --- a/test/JDBC/expected/BABEL-3204-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3204-vu-prepare.out @@ -1,9 +1,3 @@ -CREATE DATABASE db_babel_3204; -go - -USE db_babel_3204; -go - -- create ITVF which uses inbuilt functions -- function's body should not get compiled during restore CREATE FUNCTION babel_3204_complex_func diff --git a/test/JDBC/expected/BABEL-3204-vu-verify.out b/test/JDBC/expected/BABEL-3204-vu-verify.out index 3f0d82672c..7984a509bd 100644 --- a/test/JDBC/expected/BABEL-3204-vu-verify.out +++ b/test/JDBC/expected/BABEL-3204-vu-verify.out @@ -1,6 +1,3 @@ -USE db_babel_3204; -go - SELECT babel_3204_complex_func('abc def', ' '); go ~~START~~ @@ -45,9 +42,3 @@ go DROP FUNCTION babel_3204_image; go - -USE master; -go - -DROP DATABASE db_babel_3204; -go diff --git a/test/JDBC/expected/BABEL-3214.out b/test/JDBC/expected/BABEL-3214.out index c53402de2a..d770fdc5af 100644 --- a/test/JDBC/expected/BABEL-3214.out +++ b/test/JDBC/expected/BABEL-3214.out @@ -44,7 +44,7 @@ SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: REPEATABLE READ isolation level is not supported)~~ +~~ERROR (Message: Isolation level ‘REPEATABLE READ’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_repeatable_read’ config option to get PG repeatable read isolation level.)~~ SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; @@ -65,7 +65,7 @@ SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: SERIALIZABLE isolation level is not supported)~~ +~~ERROR (Message: Isolation level ‘SERIALIZABLE’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_serializable’ config option to get PG serializable isolation level.)~~ SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; @@ -98,3 +98,92 @@ smallint 5 ~~END~~ + +SELECT set_config('babelfishpg_tsql.isolation_level_repeatable_read','pg_isolation',false); +SELECT set_config('babelfishpg_tsql.isolation_level_serializable','pg_isolation',false); +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; +GO +~~START~~ +text +pg_isolation +~~END~~ + +~~START~~ +text +pg_isolation +~~END~~ + +~~START~~ +varchar +read uncommitted +~~END~~ + +~~START~~ +smallint +1 +~~END~~ + + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; +GO +~~START~~ +varchar +read committed +~~END~~ + +~~START~~ +smallint +2 +~~END~~ + + +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +GO +SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; +GO +~~START~~ +varchar +repeatable read +~~END~~ + +~~START~~ +smallint +5 +~~END~~ + + +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +GO +SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; +GO +~~START~~ +varchar +serializable +~~END~~ + +~~START~~ +smallint +4 +~~END~~ + + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +SELECT CAST(current_setting('transaction_isolation') AS VARCHAR); +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID; +GO +~~START~~ +varchar +repeatable read +~~END~~ + +~~START~~ +smallint +5 +~~END~~ + 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..cc1793c0b4 --- /dev/null +++ b/test/JDBC/expected/BABEL-3215-vu-verify.out @@ -0,0 +1,765 @@ +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 u.c1 FROM unionorder1 u +UNION +SELECT c2 FROM unionorder2 +ORDER BY c1; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +SELECT u.c1 FROM unionorder1 u +UNION ALL +SELECT u.c1 FROM unionorder1 u +ORDER BY u.c1; +go +~~START~~ +int +1 +1 +2 +2 +3 +3 +~~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 unionorder1 u +UNION +SELECT c2 FROM unionorder2 +ORDER BY unionorder1.c1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid reference to FROM-clause entry for table "unionorder1")~~ + + +SELECT u.c1 FROM dbo.unionorder1 u +UNION +SELECT c2 FROM dbo.unionorder2 +ORDER BY dbo.unionorder1.c1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid reference to FROM-clause entry for table "unionorder1")~~ + + +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 u.* FROM unionorder1 u +UNION +SELECT u.* FROM unionorder1 u +ORDER BY unionorder1.c1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid reference to FROM-clause entry for table "unionorder1")~~ + + +SELECT u.* FROM unionorder1 u +ORDER BY u.a +UNION +SELECT u.* FROM unionorder u +ORDER BY u.b +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "UNION")~~ + + +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 u1.c1, u2.c2 FROM unionorder1 u1, unionorder2 u2 where u1.c1 = u2.c2 +UNION ALL +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 +2#!#2 +3#!#3 +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 c1 FROM unionorder1 +ORDER BY c1 +UNION +SELECT c2 FROM unionorder2 +ORDER BY c2 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "UNION")~~ + + +SELECT u1.c1 FROM unionorder1 u1 +UNION +SELECT c2 FROM unionorder2 +WHERE c2 IN ( + SELECT c2 FROM unionorder2 + UNION + SELECT c1 FROM unionorder1 + WHERE c1 IN ( + SELECT c1 FROM unionorder1 + UNION + SELECT c2 FROM unionorder2 + ) +) +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, u1.c1; +go +~~START~~ +int#!#int +1#!#2 +2#!#2 +3#!#2 +3#!#3 +4#!#4 +~~END~~ + + +SELECT c1 FROM unionorder1 +WHERE c1 IN ( + SELECT c2 FROM unionorder2 + UNION + 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 +WHERE c1 IN ( + SELECT c2 FROM unionorder2 + UNION + SELECT c1 FROM unionorder1 +) +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 c2 FROM unionorder2 + UNION + SELECT c1 FROM unionorder1 +) u +UNION +SELECT c1 FROM unionorder1 +ORDER BY u.c2; +go +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +create view v1 as + select u1b.c1 + from unionorder1 u1 + inner join unionorder2 u2 + on u1.c1 = u2.c2 + inner join unionorder1b u1b + on u1.c1 = u1b.c1 +union + select u1b.c1 + from unionorder1 u1 + inner join unionorder2 u2 + on u1.c1 = u2.c2 + inner join unionorder1b u1b + on u1.c1 = u1b.c1 +go + +select * from v1; +go +~~START~~ +int +2 +3 +~~END~~ + + +drop view v1; +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 +~~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 + +-- BABEL-4169 resjunk issue with sort key outside tl +create table dbo.babel4169_t1 (a int, b int, c int); +create table dbo.babel4169_t2 (a int, b int, c int); +go + +insert into dbo.babel4169_t1 values (1, 2, 3), (10, 2, 3), (100, 2, 99); +insert into dbo.babel4169_t2 values (4, 5, 6), (40, 5, 6), (400, 5, 99); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + + +select sum(a), b from dbo.babel4169_t1 group by b, c +union +select sum(a), b from dbo.babel4169_t2 group by b, c +order by b +go +~~START~~ +int#!#int +11#!#2 +100#!#2 +44#!#5 +400#!#5 +~~END~~ + + +select sum(a) as sum, b from dbo.babel4169_t1 group by b, c +union +select sum(a), b from dbo.babel4169_t2 group by b, c +order by sum +go +~~START~~ +int#!#int +11#!#2 +44#!#5 +100#!#2 +400#!#5 +~~END~~ + + +select sum(a), b from dbo.babel4169_t1 group by b, c +union +select sum(a), b from dbo.babel4169_t2 group by b, c +order by c +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +CREATE FUNCTION babel4169_error_on_func_create () +RETURNS TABLE +AS +RETURN + select sum(a), b from dbo.babel4169_t1 group by b, c + union + select sum(a), b from dbo.babel4169_t2 group by b, c + order by c +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +drop table dbo.babel4169_t1; +drop table dbo.babel4169_t2; +go + +-- BABEL-4210 +create table babel4210_t1(id INT, val VARCHAR(20)); +create table babel4210_t2(t1_id INT, val VARCHAR(20)); +create table babel4210_t3(t1_id INT, val VARCHAR(20)); +go + +insert into babel4210_t1 values (1, 'a'), (2, 'b'), (3, 'c'); +insert into babel4210_t2 values (1, 'A'), (2, 'B'), (3, 'C'); +insert into babel4210_t3 values (1, 'x'), (2, 'Y'), (3, 'z'); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + + +select babel4210_t1.id, babel4210_t2.val, babel4210_t3.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +UNION +select babel4210_t1.id, babel4210_t2.val, babel4210_t3.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +ORDER BY babel4210_t3.val; +go +~~START~~ +int#!#varchar#!#varchar +1#!#A#!#x +2#!#B#!#Y +3#!#C#!#z +~~END~~ + + +select babel4210_t1.id, babel4210_t2.val, upper(babel4210_t3.val) from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +UNION +select babel4210_t1.id, babel4210_t3.val, upper(babel4210_t2.val) from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +ORDER BY upper(babel4210_t3.val); +go +~~START~~ +int#!#varchar#!#text +1#!#x#!#A +2#!#Y#!#B +3#!#z#!#C +1#!#A#!#X +2#!#B#!#Y +3#!#C#!#Z +~~END~~ + + +select babel4210_t1.id, babel4210_t2.val, upper(babel4210_t3.val) from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +UNION +select babel4210_t1.id, babel4210_t3.val, upper(babel4210_t2.val) from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +ORDER BY babel4210_t3.val; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +select babel4210_t1.id, babel4210_t2.val, babel4210_t3.t1_id from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +UNION +select babel4210_t1.id, babel4210_t2.val, babel4210_t3.t1_id from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +ORDER BY babel4210_t3.val; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +select babel4210_t3.val from babel4210_t3 +UNION +select babel4210_t1.val from babel4210_t1 +ORDER BY (CASE WHEN babel4210_t3.val = 'b' THEN 1 ELSE 2 END) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +select DISTINCT babel4210_t1.id, babel4210_t2.val, babel4210_t3.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +UNION +select babel4210_t1.id, babel4210_t2.val, babel4210_t3.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +ORDER BY babel4210_t2.val; +go +~~START~~ +int#!#varchar#!#varchar +1#!#A#!#x +2#!#B#!#Y +3#!#C#!#z +~~END~~ + + +select COUNT(DISTINCT babel4210_t3.val), babel4210_t2.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +GROUP BY babel4210_t2.val, babel4210_t3.val +UNION ALL +select COUNT(DISTINCT babel4210_t3.val), babel4210_t2.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +GROUP BY babel4210_t2.val, babel4210_t3.val +ORDER BY babel4210_t3.val; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +select COUNT(DISTINCT babel4210_t3.val), babel4210_t2.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +GROUP BY babel4210_t2.val +UNION +select COUNT(DISTINCT babel4210_t3.val), babel4210_t2.val from babel4210_t1 +inner join babel4210_t2 on babel4210_t1.id = babel4210_t2.t1_id +inner join babel4210_t3 on babel4210_t1.id = babel4210_t3.t1_id +GROUP BY babel4210_t2.val +ORDER BY COUNT(DISTINCT babel4210_t3.val), babel4210_t2.val; +go +~~START~~ +int#!#varchar +1#!#A +1#!#B +1#!#C +~~END~~ + + +select val from babel4210_t1 +UNION +select t1_id from babel4210_t2 +ORDER BY babel4210_t1.id +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.)~~ + + +WITH babel4210_cte (id, val) AS +( + select babel4210_t1.id, babel4210_t3.val FROM babel4210_t1 + INNER JOIN babel4210_t3 ON babel4210_t1.id = babel4210_t3.t1_id + UNION + select babel4210_t1.id, babel4210_t1.val from babel4210_t1 + INNER JOIN babel4210_t3 ON babel4210_t1.id = babel4210_t3.t1_id +) +SELECT babel4210_cte.* FROM babel4210_cte +UNION ALL +SELECT babel4210_cte.* FROM babel4210_cte +ORDER BY babel4210_cte.val, babel4210_cte.id; +GO +~~START~~ +int#!#varchar +1#!#a +1#!#a +2#!#b +2#!#b +3#!#c +3#!#c +1#!#x +1#!#x +2#!#Y +2#!#Y +3#!#z +3#!#z +~~END~~ + + +WITH babel4210_cte (id, val) AS +( + select babel4210_t1.id, babel4210_t3.val FROM babel4210_t1 + INNER JOIN babel4210_t3 ON babel4210_t1.id = babel4210_t3.t1_id + UNION + select babel4210_t1.id, babel4210_t1.val from babel4210_t1 + INNER JOIN babel4210_t3 ON babel4210_t1.id = babel4210_t3.t1_id +) +SELECT babel4210_cte.* FROM babel4210_cte +INTERSECT +SELECT babel4210_cte.* FROM babel4210_cte +ORDER BY babel4210_cte.val, babel4210_cte.id; +GO +~~START~~ +int#!#varchar +1#!#a +2#!#b +3#!#c +1#!#x +2#!#Y +3#!#z +~~END~~ + + +select top 2 babel4210_t1.id from babel4210_t1 +union +select top 1 babel4210_t2.t1_id from babel4210_t2 +ORDER BY babel4210_t2.t1_id DESC +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: missing FROM-clause entry for table "babel4210_t2")~~ + + +drop table babel4210_t1; +drop table babel4210_t2; +drop table babel4210_t3; +go diff --git a/test/JDBC/expected/BABEL-3221-vu-prepare.out b/test/JDBC/expected/BABEL-3221-vu-prepare.out index 319163c45d..058b604136 100644 --- a/test/JDBC/expected/BABEL-3221-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3221-vu-prepare.out @@ -1,9 +1,3 @@ -CREATE DATABASE db_babel_3221; -go - -USE db_babel_3221; -go - CREATE TABLE babel_3221_table_1 (id INT, unique_id varchar(200), amount money); INSERT INTO babel_3221_table_1(id, unique_id, amount) VALUES(1, '0E984725-C51C-4BF4-9960-E1C80E27ABA0', $2); go diff --git a/test/JDBC/expected/BABEL-3221-vu-verify.out b/test/JDBC/expected/BABEL-3221-vu-verify.out index f07146248e..4153404c80 100644 --- a/test/JDBC/expected/BABEL-3221-vu-verify.out +++ b/test/JDBC/expected/BABEL-3221-vu-verify.out @@ -1,6 +1,3 @@ -USE db_babel_3221; -go - SELECT * FROM babel_3221_view; go ~~START~~ @@ -28,9 +25,3 @@ go DROP TABLE babel_3221_table_2; go - -USE master; -go - -DROP DATABASE db_babel_3221; -go diff --git a/test/JDBC/expected/BABEL-3293.out b/test/JDBC/expected/BABEL-3293.out index 174aa96ac9..35d115945d 100644 --- a/test/JDBC/expected/BABEL-3293.out +++ b/test/JDBC/expected/BABEL-3293.out @@ -704,7 +704,7 @@ Hash Join Merge Cond: (babel_3293_t1.b1 = babel_3293_t3.b3) -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 -> Sort - Sort Key: babel_3293_t3.b3 + Sort Key: babel_3293_t3.b3 NULLS FIRST -> Seq Scan on babel_3293_t3 -> Hash -> Seq Scan on babel_3293_t2 @@ -1003,7 +1003,7 @@ Merge Left Join -> Index Scan using babel_3293_t2_pkey on babel_3293_t2 Index Cond: (a2 = t1.a1) -> Sort - Sort Key: babel_3293_t3.b3 + Sort Key: babel_3293_t3.b3 NULLS FIRST -> Seq Scan on babel_3293_t3 ~~END~~ diff --git a/test/JDBC/expected/BABEL-3326-vu-cleanup.out b/test/JDBC/expected/BABEL-3326-vu-cleanup.out new file mode 100644 index 0000000000..942e153a59 --- /dev/null +++ b/test/JDBC/expected/BABEL-3326-vu-cleanup.out @@ -0,0 +1,54 @@ +-- tsql user=jdbc_user password=12345678 +USE master +GO + +DROP TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] +GO + +DROP TABLE db.babel_3326_Employees +GO + +DROP SCHEMA db +GO + +REVOKE SELECT,UPDATE,INSERT,DELETE ON dbo.babel_3326_Employees TO babel_3326_non_owner +GO + +DROP TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +DROP TRIGGER TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +GO +DROP TABLE babel_3326_Employees +GO + +drop trigger babel_3326_t1_trigger +GO + +drop trigger babel_3326_t2_trigger +GO + +drop trigger babel_3326_t3_trigger +GO + +drop table babel_3326_t1; +GO + +drop table babel_3326_t2; +GO + +drop table babel_3326_t3; +GO + +DROP USER babel_3326_u1 +GO + +DROP DATABASE babel_3326_db1 +GO + +DROP LOGIN babel_3326_u1 +GO + +DROP USER babel_3326_non_owner +GO + +DROP LOGIN babel_3326_non_owner +GO diff --git a/test/JDBC/expected/BABEL-3326-vu-prepare.out b/test/JDBC/expected/BABEL-3326-vu-prepare.out new file mode 100644 index 0000000000..f8289d5611 --- /dev/null +++ b/test/JDBC/expected/BABEL-3326-vu-prepare.out @@ -0,0 +1,158 @@ +-- tsql user=jdbc_user password=12345678 +-- Preparation +USE master +GO + +CREATE LOGIN babel_3326_non_owner WITH PASSWORD = '12345678' +GO + +CREATE USER babel_3326_non_owner +GO + +CREATE LOGIN babel_3326_u1 WITH PASSWORD = '12345678' +GO + +CREATE DATABASE babel_3326_db1 +GO + +CREATE USER babel_3326_u1 FOR LOGIN babel_3326_u1 +GO + +CREATE TABLE babel_3326_Employees( + EmployeeID INT IDENTITY(1,1) PRIMARY KEY, + EmployeeName VARCHAR(50) NOT NULL, + EmployeeAddress VARCHAR(50) NOT NULL, + MonthSalary NUMERIC(10,2) NOT NULL +) +GO + +INSERT INTO dbo.babel_3326_Employees +( + EmployeeName, + EmployeeAddress, + MonthSalary +) +VALUES +( 'Temp Name1', + 'Temp Address 1', + 10000 + ), +( 'Temp Name2', + 'Temp Address 2', + 10000 +), +( 'Temp Name3', + 'Temp Address 3', + 30000 +), +( 'Temp Name4', + 'Temp Address 4', + 10000 +) +GO +~~ROW COUNT: 4~~ + + +CREATE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +FOR INSERT +AS + SELECT 'Trigger dbo.TR_ins Invoked' +GO + +CREATE TRIGGER [dbo].[TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +FOR UPDATE +AS + SELECT 'Trigger dbo.TR_upd Invoked' +GO + +CREATE TRIGGER [dbo].[TR_temp_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +FOR INSERT +AS + SELECT 'Trigger dbo.TR_temp Invoked' +GO + +GRANT SELECT,UPDATE,INSERT,DELETE ON dbo.babel_3326_Employees TO babel_3326_non_owner +GO + +-- creating another table in different schema with same table name +CREATE SCHEMA db +GO + +CREATE TABLE db.babel_3326_Employees( + EmployeeID INT IDENTITY(1,1) PRIMARY KEY, + EmployeeName VARCHAR(50) NOT NULL, + EmployeeAddress VARCHAR(50) NOT NULL, + MonthSalary NUMERIC(10,2) NOT NULL +) +GO + +INSERT INTO db.babel_3326_Employees +( + EmployeeName, + EmployeeAddress, + MonthSalary +) +VALUES +( 'Temp Name1', + 'Temp Address 1', + 10000 + ), +( 'Temp Name2', + 'Temp Address 2', + 10000 +), +( 'Temp Name3', + 'Temp Address 3', + 30000 +), +( 'Temp Name4', + 'Temp Address 4', + 10000 +) +GO +~~ROW COUNT: 4~~ + + +CREATE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +FOR INSERT +AS + SELECT 'Trigger db.TR_ins Invoked' +GO + +create table babel_3326_t1 (a varchar) +GO + +create trigger babel_3326_t1_trigger on babel_3326_t1 instead of insert as +begin + select count(*) from inserted; +end; +GO + +create table babel_3326_t2 (a varchar) +GO + +insert into babel_3326_t2 values ('1'); +GO +~~ROW COUNT: 1~~ + + +create trigger babel_3326_t2_trigger on babel_3326_t2 instead of delete as +begin + select count(*) from deleted; +end; +GO + +create table babel_3326_t3 (a varchar) +GO + +insert into babel_3326_t3 values ('2'); +GO +~~ROW COUNT: 1~~ + + +create trigger babel_3326_t3_trigger on babel_3326_t3 instead of update as +begin + select count(*) from deleted; + select count(*) from inserted; +end; +GO diff --git a/test/JDBC/expected/BABEL-3326-vu-verify.out b/test/JDBC/expected/BABEL-3326-vu-verify.out new file mode 100644 index 0000000000..596d5ac935 --- /dev/null +++ b/test/JDBC/expected/BABEL-3326-vu-verify.out @@ -0,0 +1,1171 @@ +-- tsql user=jdbc_user password=12345678 + +-- Verification +-- Check support for following syntax +-- ALTER TABLE { database_name.schema_name.table_name | schema_name.table_name | table_name } +-- { ENABLE | DISABLE } TRIGGER +-- { ALL | trigger_name [ ,...n ] } +USE master; +GO + +-- reset password +ALTER LOGIN babel_3326_non_owner WITH PASSWORD = '12345678' +GO + +ALTER LOGIN babel_3326_u1 WITH PASSWORD = '12345678' +GO + +-- triggers should be enabled by default +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE [babel_3326_Employees] DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE babel_3326_Employees ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE dbo.babel_3326_Employees DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE [dbo].[babel_3326_Employees] ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE [master].[dbo].[babel_3326_Employees] DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE master.dbo.babel_3326_Employees ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be enabled by default +UPDATE master.dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE babel_3326_Employees DISABLE TRIGGER ALL +GO + +-- All triggers on table babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +ALTER TABLE [babel_3326_Employees] ENABLE TRIGGER ALL +GO + +-- All triggers on table babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ALTER TABLE [babel_3326_Employees] DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +ALTER TABLE babel_3326_Employees ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +GO + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + + + +-- Check support for following syntax +-- { ENABLE | DISABLE } TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } +-- ON { table_name } [ ; ] +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON babel_3326_Employees +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +DISABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +ENABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON babel_3326_Employees +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + + +DISABLE TRIGGER ALL ON babel_3326_Employees +GO + +-- All triggers on table babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +ENABLE TRIGGER ALL ON [babel_3326_Employees] +GO + +-- All triggers on table babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees ON babel_3326_Employees +GO + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~START~~ +varchar +Trigger dbo.TR_temp Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + + +-- Test cases to check dropping of a disabled trigger +DISABLE TRIGGER TR_temp_babel_3326_Employees ON babel_3326_Employees +GO + +DROP TRIGGER TR_temp_babel_3326_Employees +GO + + +-- tsql user=babel_3326_non_owner password=12345678 +-- Test case to check if non-owner user of the table has select/insert/update/delete access but should not be allowed to enable/disable a trigger +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Should throw error as babel_3326_non_owner cannot enable/disable trigger +ALTER TABLE master.dbo.babel_3326_Employees DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table babel_3326_employees)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees should not be disabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Should throw error as babel_3326_non_owner cannot enable/disable trigger +ALTER TABLE master.dbo.babel_3326_Employees ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table babel_3326_employees)~~ + + +-- Should throw error as babel_3326_non_owner cannot enable/disable trigger +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON master.dbo.babel_3326_Employees +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table babel_3326_employees)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees should not be disabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Should throw error as babel_3326_non_owner cannot enable/disable trigger +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON master.dbo.babel_3326_Employees +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table babel_3326_employees)~~ + + + +-- tsql user=jdbc_user password=12345678 +-- Cross database enabling/disabling of trigger +USE babel_3326_db1 +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- should throw error as, currently babelfish doesn't support alter table cross db referencing +ALTER TABLE [master].[dbo].[babel_3326_Employees] DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table babel_3326_employees)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees should not be disabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- should throw error as, currently babelfish doesn't support alter table cross db referencing +ALTER TABLE master.dbo.babel_3326_Employees ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: must be owner of table babel_3326_employees)~~ + + +-- should throw error as { ENABLE | DISABLE } TRIGGER syntax doesn't support cross db reference +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON master.dbo.babel_3326_Employees +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot disable trigger on 'master.dbo.babel_3326_employees' as the target is not in the current database.)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees should not be disabled +INSERT INTO master.dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- should throw error as { ENABLE | DISABLE } TRIGGER syntax doesn't support cross db reference +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON master.dbo.babel_3326_Employees +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot enable trigger on 'master.dbo.babel_3326_employees' as the target is not in the current database.)~~ + + +USE master +GO + + +-- Test cases if user tries to enable/disable nonexistent trigger +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be enabled by default +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees SET MonthSalary = 3333 WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Should throw error and none of the triggers should be disabled +ALTER TABLE [babel_3326_Employees] DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_trig_does_not_exist, [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] +GO +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: trigger "tr_trig_does_not_exist" for table "babel_3326_employees" does not exist)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should not be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Disable triggers TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- Should throw error and none of the triggers should be enabled +ALTER TABLE [babel_3326_Employees] ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_trig_does_not_exist, [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] +GO +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: trigger "tr_trig_does_not_exist" for table "babel_3326_employees" does not exist)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should not be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +-- Enable triggers TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- Should throw error and none of the triggers should be enabled +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_trig_does_not_exist, [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: trigger "tr_trig_does_not_exist" for table "babel_3326_employees" does not exist)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should not be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- Disable triggers TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- Should throw error and none of the triggers should be enabled +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_trig_does_not_exist, TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees ON babel_3326_Employees +GO +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: trigger "tr_trig_does_not_exist" for table "babel_3326_employees" does not exist)~~ + + +-- TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should not be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~ROW COUNT: 1~~ + + +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +-- Enable triggers TR_ins_안녕하세요_babel_3326_Employees and TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO + + +-- psql +-- Test cases if user tries to enable/disable trigger . on table . +-- if both schemas have tables with same name and each table have trigger with same trigger name +ALTER TABLE master_dbo.babel_3326_Employees OWNER TO master_babel_3326_u1; +GO +ALTER TABLE master_db.babel_3326_Employees OWNER TO master_babel_3326_u1; +GO + +-- tsql user=babel_3326_u1 password=12345678 + +-- will work; as default schema is dbo, relation dbo.babel_3326_Employees will be used below +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + + +-- will work; as default schema is dbo, relation dbo.babel_3326_Employees will be used below +ENABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +DISABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + + +-- will not work, throw error; as default schema is dbo, relation dbo.babel_3326_Employees will be used below +ENABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger db.tr_ins_안녕하세요_babel_3326_employees on table dbo.babel_3326_employees does not exists or table dbo.babel_3326_employees does not exists)~~ + + +DISABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger db.tr_ins_안녕하세요_babel_3326_employees on table dbo.babel_3326_employees does not exists or table dbo.babel_3326_employees does not exists)~~ + + + +ALTER USER babel_3326_u1 WITH DEFAULT_SCHEMA=db +GO + +-- will work; as default schema is db, relation db.babel_3326_Employees will be used below +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + + +-- will not work, throw error; as default schema is db, relation db.babel_3326_Employees will be used below +ENABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger dbo.tr_ins_안녕하세요_babel_3326_employees on table db.babel_3326_employees does not exists or table db.babel_3326_employees does not exists)~~ + + +DISABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger dbo.tr_ins_안녕하세요_babel_3326_employees on table db.babel_3326_employees does not exists or table db.babel_3326_employees does not exists)~~ + + + +-- will work; as default schema is db, relation db.babel_3326_Employees will be used below +ENABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +DISABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + + +ALTER USER babel_3326_u1 WITH DEFAULT_SCHEMA=dbo +GO + +-- will work; +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +GO + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +GO + + +-- will work +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +GO + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +GO + + +-- will work +ENABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +GO + +DISABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +GO + + +-- will not work, throw error +ENABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger dbo.tr_ins_안녕하세요_babel_3326_employees on table db.babel_3326_employees does not exists or table db.babel_3326_employees does not exists)~~ + + +DISABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger dbo.tr_ins_안녕하세요_babel_3326_employees on table db.babel_3326_employees does not exists or table db.babel_3326_employees does not exists)~~ + + + +-- will not work, throw error +ENABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger db.tr_ins_안녕하세요_babel_3326_employees on table dbo.babel_3326_employees does not exists or table dbo.babel_3326_employees does not exists)~~ + + +DISABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [dbo].[babel_3326_Employees] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Trigger db.tr_ins_안녕하세요_babel_3326_employees on table dbo.babel_3326_employees does not exists or table dbo.babel_3326_employees does not exists)~~ + + + +-- will work +ENABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +GO + +DISABLE TRIGGER [db].[TR_ins_안녕하세요_babel_3326_Employees] ON [db].[babel_3326_Employees] +GO + +-- psql +ALTER TABLE master_dbo.babel_3326_Employees OWNER TO master_dbo; +GO +ALTER TABLE master_db.babel_3326_Employees OWNER TO master_dbo; +GO + + +-- tsql user=jdbc_user password=12345678 + +-- Test cases for behaviour of enable/disable of trigger in transactions +ENABLE TRIGGER TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees ON [babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~ROW COUNT: 1~~ + + +-- TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be enabled +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +BEGIN TRAN babel_3326_transaction1 +GO + +-- Enable trigger TR_ins_안녕하세요_babel_3326_Employees +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- Disable trigger TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees +DISABLE TRIGGER [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON [babel_3326_Employees] +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be enabled +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~START~~ +varchar +Trigger dbo.TR_ins Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +-- TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be disabled +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~ROW COUNT: 1~~ + + +ROLLBACK TRAN babel_3326_transaction1 +GO + +-- TR_ins_안녕하세요_babel_3326_Employees should be disabled as rollback of transaction will also revert the effect of statements in the transaction +INSERT INTO dbo.babel_3326_Employees ( EmployeeName, EmployeeAddress, MonthSalary ) +VALUES ( 'Temp Name5' , 'Address Name 5', 4000) +GO +~~ROW COUNT: 1~~ + + +-- TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees should be enabled +-- as rollback of transaction will also revert the effect of statements in the transaction +UPDATE dbo.babel_3326_Employees +SET MonthSalary = 3333 +WHERE EmployeeID = 2; +GO +~~START~~ +varchar +Trigger dbo.TR_upd Invoked +~~END~~ + +~~ROW COUNT: 1~~ + + +DISABLE TRIGGER TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees ON [babel_3326_Employees] +GO + + +-- Test cases for not-supported variants +-- Statements with following syntax throw error as DDL triggers are not supported in babelfish +-- { ENABLE | DISABLE } TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } +-- ON { DATABASE | ALL SERVER } [ ; ] +USE master +GO + +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON DATABASE +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees] ON ALL SERVER +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +DISABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON DATABASE +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +ENABLE TRIGGER [dbo].[TR_ins_안녕하세요_babel_3326_Employees] ON ALL SERVER +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +DISABLE TRIGGER ALL ON ALL SERVER +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +ENABLE TRIGGER ALL ON DATABASE +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +DISABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], [TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees] ON DATABASE +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +ENABLE TRIGGER [TR_ins_안녕하세요_babel_3326_Employees], TR_upd_abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_babel_3326_Employees ON ALL SERVER +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DDL trigger' is not currently supported in Babelfish.)~~ + + +-- The instead of trigger is on and there'll no rows will be inserted +insert into babel_3326_t1 values ('1'); +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +DISABLE trigger babel_3326_t1_trigger on babel_3326_t1 +GO + +insert into babel_3326_t1 values ('1'); +GO +~~ROW COUNT: 1~~ + + +-- The instead of trigger is disabled and new rows are inserted into the table +select * from babel_3326_t1; +GO +~~START~~ +varchar +1 +~~END~~ + + +delete from babel_3326_t2; +GO +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +select * from babel_3326_t2; +GO +~~START~~ +varchar +1 +~~END~~ + + +DISABLE trigger babel_3326_t2_trigger on babel_3326_t2 +GO + +delete from babel_3326_t2; +GO +~~ROW COUNT: 1~~ + + +select * from babel_3326_t2; +GO +~~START~~ +varchar +~~END~~ + + +update babel_3326_t3 set a = '3'; +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + + +select * from babel_3326_t3; +GO +~~START~~ +varchar +2 +~~END~~ + + +DISABLE trigger babel_3326_t3_trigger on babel_3326_t3 +GO + +update babel_3326_t3 set a = '3'; +GO +~~ROW COUNT: 1~~ + + +select * from babel_3326_t3; +GO +~~START~~ +varchar +3 +~~END~~ + + +-- BABEL-4523 +USE babel_3326_db1 +go + +CREATE TABLE testdb_t1(TransactionID int NOT NULL) +GO + +-- should error out because trigger does not exist: +ALTER TABLE testdb_t1 DISABLE TRIGGER testdb_t1_trigger +go +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: trigger "testdb_t1_trigger" for table "testdb_t1" does not exist)~~ + + +CREATE PROCEDURE testdb_proc1 +AS +BEGIN + ALTER TABLE testdb_t1 DISABLE TRIGGER testdb_t1_trigger +END +GO + +-- should not crash +EXECUTE testdb_proc1 +go +~~ERROR (Code: 4920)~~ + +~~ERROR (Message: trigger "testdb_t1_trigger" for table "testdb_t1" does not exist)~~ + + +USE master +GO + diff --git a/test/JDBC/expected/BABEL-3392-vu-prepare.out b/test/JDBC/expected/BABEL-3392-vu-prepare.out new file mode 100644 index 0000000000..90d8f6f64c --- /dev/null +++ b/test/JDBC/expected/BABEL-3392-vu-prepare.out @@ -0,0 +1,25 @@ +CREATE VIEW babel3392_v1 +AS + SELECT NULL AS Col1 + UNION + SELECT CAST('1' AS CHAR(10)) AS Col1 +; +GO + +CREATE VIEW babel3392_v2 +AS + SELECT CAST('1' AS CHAR(4)) AS Col1 + UNION + SELECT CAST(N'ΘЖऌฒ' AS NCHAR(8)) AS Col1 +; +GO + +CREATE VIEW babel3392_v3 +AS + SELECT NULL + UNION + SELECT NULL + UNION + SELECT CAST('1' AS CHAR(8)) +; +GO diff --git a/test/JDBC/expected/BABEL-3392-vu-verify.out b/test/JDBC/expected/BABEL-3392-vu-verify.out new file mode 100644 index 0000000000..0985c7dbe3 --- /dev/null +++ b/test/JDBC/expected/BABEL-3392-vu-verify.out @@ -0,0 +1,2099 @@ +SELECT * FROM babel3392_v1 ORDER BY 1; +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT * FROM babel3392_v2 ORDER BY 1; +GO +~~START~~ +nchar +1 +ΘЖऌฒ +~~END~~ + + +SELECT * FROM babel3392_v3 ORDER BY 1; +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT babel3392_v1.* , babel3392_v2.*, babel3392_v3.* FROM babel3392_v1, babel3392_v2, babel3392_v3 +UNION ALL +SELECT babel3392_v2.* , babel3392_v3.*, babel3392_v1.* FROM babel3392_v1, babel3392_v2, babel3392_v3 +ORDER BY 1, 2, 3 +GO +~~START~~ +nchar#!#nchar#!#char +#!#1 #!# +#!#1 #!#1 +#!#ΘЖऌฒ #!# +#!#ΘЖऌฒ #!#1 +1 #!##!# +1 #!##!#1 +1 #!#1 #!# +1 #!#1 #!# +1 #!#1 #!#1 +1 #!#1 #!#1 +1 #!#ΘЖऌฒ #!# +1 #!#ΘЖऌฒ #!#1 +ΘЖऌฒ #!##!# +ΘЖऌฒ #!##!#1 +ΘЖऌฒ #!#1 #!# +ΘЖऌฒ #!#1 #!#1 +~~END~~ + + +SELECT NULL, NULL +UNION ALL +SELECT * FROM (SELECT babel3392_v1.* , babel3392_v2.* FROM babel3392_v1, babel3392_v2) t1 +ORDER BY 1, 2 +GO +~~START~~ +char#!#nchar +#!# +#!#1 +#!#ΘЖऌฒ +1 #!#1 +1 #!#ΘЖऌฒ +~~END~~ + + +DROP view babel3392_v1; +DROP view babel3392_v2; +DROP view babel3392_v3; +GO + +SELECT CAST('1' AS CHAR(10)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT NULL AS Col1 +UNION +SELECT CAST('1' AS CHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT CAST('1' AS NCHAR(10)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar + +1 +~~END~~ + + +SELECT NULL AS Col1 +UNION +SELECT CAST('1' AS NCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar + +1 +~~END~~ + + +SELECT CAST(1 AS BINARY(10)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +binary + +00000000000000000001 +~~END~~ + + +SELECT NULL AS Col1 +UNION +SELECT CAST(1 AS BINARY(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +binary + +00000000000000000001 +~~END~~ + + +SELECT CAST(1 AS VARCHAR(10)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +varchar + +1 +~~END~~ + + +SELECT NULL AS Col1 +UNION +SELECT CAST(1 AS VARCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +varchar + +1 +~~END~~ + + +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +nvarchar + +ΘЖऌฒ +~~END~~ + + +SELECT NULL AS Col1 +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nvarchar + +ΘЖऌฒ +~~END~~ + + +SELECT CAST(1 AS VARCHAR(10)) AS Col1 +UNION +SELECT CAST('2' AS CHAR(15)) +ORDER BY 1 +GO +~~START~~ +varchar +1 +2 +~~END~~ + + +SELECT CAST('2' AS CHAR(15)) +UNION +SELECT CAST(1 AS VARCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +varchar +1 +2 +~~END~~ + + +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) AS Col1 +UNION +SELECT CAST('2' AS CHAR(15)) +ORDER BY 1 +GO +~~START~~ +nvarchar +2 +ΘЖऌฒ +~~END~~ + + +SELECT CAST('2' AS CHAR(15)) +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nvarchar +2 +ΘЖऌฒ +~~END~~ + + +SELECT CAST(1 AS VARCHAR(10)) AS Col1 +UNION +SELECT CAST(N'Жऌ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nchar +1 +Жऌ +~~END~~ + + +SELECT CAST('2' AS CHAR(15)) +UNION +SELECT CAST(N'Жऌ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nchar +2 +Жऌ +~~END~~ + + +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) AS Col1 +UNION +SELECT CAST(N'Жऌ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nvarchar +ΘЖऌฒ +Жऌ +~~END~~ + + +SELECT CAST(N'Жऌ' AS NCHAR(15)) +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nvarchar +ΘЖऌฒ +Жऌ +~~END~~ + + +SELECT NULL +UNION +SELECT CAST(1 AS VARCHAR(10)) AS Col1 +UNION +SELECT CAST(N'Жऌ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nchar + +1 +Жऌ +~~END~~ + + +SELECT CAST('2' AS CHAR(15)) +UNION +SELECT CAST(N'Жऌ' AS NCHAR(15)) +UNION +SELECT NULL +ORDER BY 1 +GO +~~START~~ +nchar + +2 +Жऌ +~~END~~ + + +SELECT NULL +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) +UNION +SELECT CAST(N'Жऌ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nvarchar + +ΘЖऌฒ +Жऌ +~~END~~ + + +SELECT CAST(N'Жऌ' AS NCHAR(15)) +UNION +SELECT NULL +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(10)) +ORDER BY 1 +GO +~~START~~ +nvarchar + +ΘЖऌฒ +Жऌ +~~END~~ + + +SELECT CAST(1 AS CHAR(1)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT CAST('1' AS CHAR(255)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT CAST('1' AS CHAR(15)) AS Col1 +UNION +SELECT CAST('2' AS CHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +char +1 +2 +~~END~~ + + +SELECT CAST('1' AS CHAR(10)) AS Col1 +UNION +SELECT CAST('2' AS CHAR(15)) AS Col1 +ORDER BY 1 +GO +~~START~~ +char +1 +2 +~~END~~ + + +SELECT CAST('1' AS NCHAR(15)) AS Col1 +UNION +SELECT CAST('2' AS NCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar +1 +2 +~~END~~ + + +SELECT CAST('1' AS NCHAR(10)) AS Col1 +UNION +SELECT CAST('2' AS NCHAR(15)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar +1 +2 +~~END~~ + + +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(10)) AS Col1 +UNION +SELECT NULL AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar + +ΘЖऌฒ +~~END~~ + + +SELECT NULL AS Col1 +UNION +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(10)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar + +ΘЖऌฒ +~~END~~ + + +SELECT CAST(1 AS BINARY(4)) AS Col1 +UNION +SELECT CAST(2 AS BINARY(8)) AS Col1 +ORDER BY 1 +GO +~~START~~ +binary +0000000000000002 +0000000100000000 +~~END~~ + + +SELECT CAST(1 AS BINARY(4)) AS Col1 +UNION +SELECT CAST(2 AS BINARY(8)) AS Col1 +ORDER BY 1 +GO +~~START~~ +binary +0000000000000002 +0000000100000000 +~~END~~ + + +SELECT CAST('1' AS CHAR(4)) AS Col1 +UNION +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(8)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar +1 +ΘЖऌฒ +~~END~~ + + +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(8)) AS Col1 +UNION +SELECT CAST('1' AS CHAR(4)) AS Col1 +ORDER BY 1 +GO +~~START~~ +nchar +1 +ΘЖऌฒ +~~END~~ + + +SELECT CAST('1' AS CHAR(4)) +INTERSECT +SELECT CAST('1' AS CHAR(8)) +ORDER BY 1 +GO +~~START~~ +char +1 +~~END~~ + + +SELECT CAST('1' AS CHAR(8)) +INTERSECT +SELECT CAST('1' AS CHAR(4)) +ORDER BY 1 +GO +~~START~~ +char +1 +~~END~~ + + +SELECT CAST('1' AS CHAR(8)) +INTERSECT +SELECT CAST(N'1' AS NCHAR(4)) +ORDER BY 1 +GO +~~START~~ +nchar +1 +~~END~~ + + +SELECT CAST('1' AS CHAR(4)) +EXCEPT +SELECT CAST('1' AS CHAR(8)) +ORDER BY 1 +GO +~~START~~ +char +~~END~~ + + +SELECT CAST('1' AS CHAR(8)) +EXCEPT +SELECT CAST('1' AS CHAR(4)) +ORDER BY 1 +GO +~~START~~ +char +~~END~~ + + +SELECT CAST('1' AS NCHAR(8)) +EXCEPT +SELECT CAST('2' AS CHAR(4)) +ORDER BY 1 +GO +~~START~~ +nchar +1 +~~END~~ + + +-- Multiple Unions -- +SELECT CAST('1' AS CHAR(8)) +UNION +SELECT NULL +UNION +SELECT NULL +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT NULL +UNION +SELECT CAST('1' AS CHAR(8)) +UNION +SELECT NULL +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT NULL +UNION +SELECT NULL +GO +~~START~~ +int + +~~END~~ + + +SELECT NULL +UNION ALL +SELECT NULL +GO +~~START~~ +int + + +~~END~~ + + +SELECT NULL +UNION +SELECT NULL +UNION +SELECT CAST('1' AS CHAR(8)) +ORDER BY 1 +GO +~~START~~ +char + +1 +~~END~~ + + +SELECT NULL +UNION +SELECT NULL +UNION +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(8)) +ORDER BY 1 +GO +~~START~~ +nchar + +ΘЖऌฒ +~~END~~ + + +SELECT CAST('2' AS CHAR(16)) +UNION +SELECT CAST('1' AS CHAR(8)) +UNION +SELECT NULL +ORDER BY 1 +GO +~~START~~ +char + +1 +2 +~~END~~ + + +SELECT CAST('2' AS CHAR(16)) +UNION +SELECT CAST('1' AS NCHAR(8)) +UNION +SELECT NULL +ORDER BY 1 +GO +~~START~~ +nchar + +1 +2 +~~END~~ + + +SELECT CAST('2' AS NCHAR(16)) +UNION +SELECT CAST('1' AS NCHAR(8)) +UNION +SELECT NULL +ORDER BY 1 +GO +~~START~~ +nchar + +1 +2 +~~END~~ + + +SELECT CAST('2' AS NCHAR(16)) +UNION ALL +SELECT CAST('1' AS NCHAR(8)) +UNION ALL +SELECT NULL +ORDER BY 1 +GO +~~START~~ +nchar + +1 +2 +~~END~~ + + +SELECT NULL +UNION ALL +SELECT NULL +UNION ALL +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nchar + + +ΘЖऌฒ +~~END~~ + + +SELECT CAST('1' AS NCHAR(16)) +INTERSECT +SELECT CAST('1' AS NCHAR(8)) +INTERSECT +SELECT CAST('1' AS NCHAR(4)) +ORDER BY 1 +GO +~~START~~ +nchar +1 +~~END~~ + + +SELECT CAST('1' AS NCHAR(16)) +INTERSECT +SELECT CAST('2' AS NCHAR(8)) +INTERSECT +SELECT CAST('1' AS NCHAR(4)) +ORDER BY 1 +GO +~~START~~ +nchar +~~END~~ + + +SELECT NULL +INTERSECT +SELECT NULL +INTERSECT +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(15)) +ORDER BY 1 +GO +~~START~~ +nchar +~~END~~ + + +SELECT set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +SET babelfish_showplan_all ON +GO + +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(8)) AS Col1 +UNION +SELECT CAST('1' AS CHAR(4)) AS Col1 +ORDER BY 1 +GO +~~START~~ +text +Query Text: SELECT CAST(N'????' AS NCHAR(8)) AS Col1 +UNION +SELECT CAST('1' AS CHAR(4)) AS Col1 +ORDER BY 1 +Sort + Sort Key: ('???? '::"nchar"(8)) NULLS FIRST + -> Unique + -> Sort + Sort Key: ('???? '::"nchar"(8)) + -> Append + -> Result + -> Result +~~END~~ + + +SELECT NULL +UNION +SELECT NULL +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(12)) AS Col1 +ORDER BY 1 +GO +~~START~~ +text +Query Text: SELECT NULL +UNION +SELECT NULL +UNION +SELECT CAST(N'????' AS NVARCHAR(12)) AS Col1 +ORDER BY 1 +Sort + Sort Key: (NULL::nvarchar(12)) NULLS FIRST + -> HashAggregate + Group Key: (NULL::nvarchar(12)) + -> Append + -> Result + -> Result + -> Result +~~END~~ + + +SELECT cast('foo' as CHAR(3)) +UNION +SELECT 'longer string' +ORDER BY 1 +GO +~~START~~ +text +Query Text: SELECT cast('foo' as CHAR(3)) +UNION +SELECT 'longer string' +ORDER BY 1 +Sort + Sort Key: ('foo'::"varchar"(13)) NULLS FIRST + -> Unique + -> Sort + Sort Key: ('foo'::"varchar"(13)) + -> Append + -> Result + -> Result +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +CREATE TABLE babel3392_nchar_tbl(a NCHAR(20)) +GO + +INSERT INTO babel3392_nchar_tbl (a) + SELECT CAST(N'ΘЖऌฒ' AS NCHAR(10)) AS Col1 + UNION + SELECT NULL AS Col1 + ORDER BY 1 +GO +~~ROW COUNT: 2~~ + + +DROP TABLE babel3392_nchar_tbl +GO + +-- Should error +WITH babel3392_recursive_cte(a) +AS ( + SELECT NULL + UNION ALL + SELECT CAST(a + 'a' AS CHAR(10)) from babel3392_recursive_cte where a != 'aaaaa' +) +SELECT a from babel3392_recursive_cte order by a +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: recursive query "babel3392_recursive_cte" column 1 has type text in non-recursive term but type bpchar(10) overall)~~ + + +WITH babel3392_recursive_cte(a) +AS ( + SELECT 'a' + UNION ALL + SELECT CAST(a + 'a' AS CHAR(10)) from babel3392_recursive_cte where a != 'aaaaa' +) +SELECT a from babel3392_recursive_cte order by a +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: recursive query "babel3392_recursive_cte" column 1 has type text in non-recursive term but type "varchar"(10) overall)~~ + + +-- COALESCE / ISNULL +SELECT ISNULL(null, cast(N'ΘЖऌฒ' as NCHAR(15))) +GO +~~START~~ +nchar +ΘЖऌฒ +~~END~~ + + +-- BABEL-4157 +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT CAST('varchar' AS VARCHAR(40)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +string +varchar +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('varchar' AS VARCHAR(40)) AS babel4157_c1 + UNION + SELECT 'string' AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +string +varchar +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT CAST('varchar' AS VARCHAR(MAX)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +string +varchar +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(40)) AS babel4157_c1 + UNION + SELECT 'string' AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +string +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#80 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(40)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +string +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#80 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(MAX)) AS babel4157_c1 + UNION + SELECT 'string' AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +string +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +CREATE TABLE babel4157_tbl2 (c1 varchar(40) not null); +go + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT c1 from babel4157_tbl2 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +string +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +DROP TABLE babel4157_tbl2 +GO + +CREATE TABLE babel4157_tbl2 (c1 nvarchar(40) not null); +go + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT N'ΘЖऌฒ' AS babel4157_c1 + UNION ALL + SELECT c1 from babel4157_tbl2 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#80 +~~END~~ + + +DROP TABLE babel4157_tbl +DROP TABLE babel4157_tbl2 +GO + +CREATE TABLE babel4157_tbl2 (c1 varchar(max) not null); +go + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT c1 from babel4157_tbl2 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +string +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +DROP TABLE babel4157_tbl2 +GO + +CREATE TABLE babel4157_tbl2 (c1 varchar(max) not null); +go + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('string' AS VARCHAR(40)) AS babel4157_c1 + UNION ALL + SELECT c1 from babel4157_tbl2 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +string +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +DROP TABLE babel4157_tbl2 +GO + +CREATE TABLE babel4157_tbl2 (c1 nvarchar(max) not null); +go + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT N'ΘЖऌฒ' AS babel4157_c1 + UNION + SELECT c1 from babel4157_tbl2 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +DROP TABLE babel4157_tbl2 +GO + +CREATE TABLE babel4157_tbl2 (c1 nvarchar(max) not null); +go + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(40)) AS babel4157_c1 + UNION ALL + SELECT c1 from babel4157_tbl2 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +DROP TABLE babel4157_tbl2 +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT CAST(N'ΘЖऌฒ' AS NCHAR(40)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nchar +string +ΘЖऌฒ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#80 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT 'string' AS babel4157_c1 + UNION + SELECT CAST('char' AS CHAR(40)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +char +string +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('char' AS CHAR(15)) AS babel4157_c1 + UNION + SELECT CAST(N'Жऌ' AS NCHAR(20)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nchar +char +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('char' AS CHAR(20)) AS babel4157_c1 + UNION + SELECT CAST('varchar' AS VARCHAR(15)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varchar +char +varchar +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#20 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('char' AS CHAR(20)) AS babel4157_c1 + UNION + SELECT CAST(N'Жऌ' AS NVARCHAR(15)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +char +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('char' AS CHAR(20)) AS babel4157_c1 + UNION + SELECT CAST(N'Жऌ' AS NVARCHAR(MAX)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +char +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +-- Currently gives wrong typmod, need to support nvarchar literals +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('char' AS CHAR(20)) AS babel4157_c1 + UNION + SELECT N'Жऌ' AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +char +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST(N'Жऌ' AS NCHAR(20)) AS babel4157_c1 + UNION + SELECT CAST('varchar' AS VARCHAR(15)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nchar +varchar +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST(N'Жऌ' AS NCHAR(20)) AS babel4157_c1 + UNION + SELECT CAST('nvarchar' AS NVARCHAR(15)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +nvarchar +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT CAST('varchar' AS VARCHAR(15)) AS babel4157_c1 + UNION + SELECT CAST(N'Жऌ' AS NVARCHAR(20)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +nvarchar +varchar +Жऌ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT cast(17 as binary(1)) AS babel4157_c1 + UNION + SELECT cast(10 as binary(2)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +binary +000A +1100 +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#2 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT cast(11 as varbinary(1)) AS babel4157_c1 + UNION + SELECT cast(10 as varbinary(2)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varbinary +000A +0B +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#2 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT cast(11 as varbinary(1)) AS babel4157_c1 + UNION + SELECT cast(10 as varbinary(max)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varbinary +0000000A +0B +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#-1 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT cast(17 as binary(1)) AS babel4157_c1 + UNION + SELECT cast(10 as varbinary(3)) AS babel4157_c1 +) AS tbl +ORDER BY 1 +GO + +SELECT * FROM babel4157_tbl ORDER BY 1 +GO +~~START~~ +varbinary +00000A +11 +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!# +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT 'string' AS babel4157_c1 +UNION +SELECT CAST('varchar' AS VARCHAR(40)) AS babel4157_c1 +ORDER BY 1 +GO +~~START~~ +varchar +string +varchar +~~END~~ + + +SELECT CAST('long string test' AS VARCHAR(MAX)) AS babel4157_c1 +UNION +SELECT CAST('foo' AS VARCHAR(4)) AS babel4157_c1 +ORDER BY 1 +GO +~~START~~ +varchar +foo +long string test +~~END~~ + + +SELECT 'string' AS babel4157_c1 +UNION +SELECT CAST('char' AS CHAR(15)) AS babel4157_c1 +ORDER BY 1 +GO +~~START~~ +varchar +char +string +~~END~~ + + +SELECT 'string' AS babel4157_c1 +UNION +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(15)) AS babel4157_c1 +ORDER BY 1 +GO +~~START~~ +nchar +string +ΘЖऌฒ +~~END~~ + + +SELECT 'string' AS babel4157_c1 +UNION +SELECT CAST(N'ΘЖऌฒ' AS NVARCHAR(40)) AS babel4157_c1 +ORDER BY 1 +GO +~~START~~ +nvarchar +string +ΘЖऌฒ +~~END~~ + + +SELECT 'char' +ORDER BY 1 +GO +~~START~~ +text +char +~~END~~ + + +SELECT 'char' +GO +~~START~~ +varchar +char +~~END~~ + + +SELECT 'foo' +UNION +SELECT 'longer string' +ORDER BY 1 +GO +~~START~~ +varchar +foo +longer string +~~END~~ + + +SELECT 'foo' +UNION +SELECT CAST('bar' AS VARCHAR(20)) +ORDER BY 1 +GO +~~START~~ +varchar +bar +foo +~~END~~ + + +SELECT 'longer string' +UNION +SELECT CAST('foo' as CHAR(3)) +ORDER BY 1 +GO +~~START~~ +varchar +foo +longer string +~~END~~ + + +SELECT CAST('foo' as CHAR(3)) +UNION +SELECT 'longer string' +ORDER BY 1 +GO +~~START~~ +varchar +foo +longer string +~~END~~ + + +SELECT 'longer string' +UNION +SELECT CAST('ऌฒ' as NCHAR(2)) +ORDER BY 1 +GO +~~START~~ +nchar +longer string +ऌฒ +~~END~~ + + +SELECT CAST('ऌฒ' as NCHAR(2)) +UNION +SELECT 'longer string' +ORDER BY 1 +GO +~~START~~ +nchar +longer string +ऌฒ +~~END~~ + + +-- VALUES +select tbl.babel3392_c1 into babel3392_vals from ( + values (CAST('1' AS CHAR(10))), (CAST(N'ΘЖऌฒ' AS NCHAR(15))), (NULL) +) as tbl(babel3392_c1) +GO + +SELECT * FROM babel3392_vals; +GO +~~START~~ +nchar +1 +ΘЖऌฒ + +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel3392_c1' +GO +~~START~~ +varchar#!#smallint +babel3392_c1#!#30 +~~END~~ + + +DROP TABLE babel3392_vals; +GO + +-- IN +SELECT 1 WHERE CAST('1' AS CHAR(10)) IN ( + CAST(N'1' AS NCHAR(10)), CAST('2' AS CHAR(20)), CAST('3' AS VARCHAR), '4', NULL +); +GO +~~START~~ +int +1 +~~END~~ + + +-- TEXT +SELECT CAST('foo' AS TEXT) UNION SELECT CAST('bar' as CHAR(10)) UNION SELECT NULL ORDER BY 1; +GO +~~START~~ +text + +bar +foo +~~END~~ + + +-- BINARY +select cast(17 as binary(1)) +UNION +select cast(10 as binary(2)) +ORDER BY 1 +GO +~~START~~ +binary +000A +1100 +~~END~~ + + +select NULL +UNION +select cast(10 as binary(2)) +ORDER BY 1 +GO +~~START~~ +binary + +000A +~~END~~ + + +-- Incorrect length +select cast(17 as varbinary(1)) UNION select cast(10 as varbinary(2)) ORDER BY 1; +GO +~~START~~ +varbinary +000A +11 +~~END~~ + + +select cast(17 as varbinary(MAX)) UNION select cast(10 as varbinary(2)) ORDER BY 1; +GO +~~START~~ +varbinary +00000011 +000A +~~END~~ + + +select cast(17 as varbinary(1)) UNION select cast(10 as varbinary(2)) union select cast(N'a' as NCHAR(10)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: UNION could not convert type "nchar" to bbf_varbinary)~~ + + +SELECT CAST(N'ΘЖऌฒ' AS NCHAR(15)) UNION select cast(10 as varbinary(2)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: UNION could not convert type varbinary to bpchar)~~ + + +SELECT CAST(1 as BIT) UNION SELECT cast(N'ab' as NCHAR(10)) UNION SELECT CAST('bar' as CHAR(10)); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: UNION could not convert type "nchar" to "bit")~~ + + +SELECT 'foo' +UNION +SELECT cast(17 as varbinary(2)) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot coerce string literal to varbinary datatype)~~ + + +SELECT 'foo' +UNION +SELECT cast(17 as varbinary(2)) +ORDER BY 1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot coerce string literal to varbinary datatype)~~ + + +SELECT cast(17 as varbinary(2)) +UNION +SELECT 'foo' +ORDER BY 1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot coerce string literal to varbinary datatype)~~ + + +SELECT 'foo' +UNION +SELECT 'bar' +UNION +SELECT cast(17 as varbinary(2)) +ORDER BY 1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: UNION could not convert type varbinary to "varchar")~~ + + +-- BABEL-1874 +SELECT DISTINCT CAST( 1 AS BIT) AS Col1 +UNION +SELECT DISTINCT NULL +GO +~~START~~ +bit +1 + +~~END~~ + + +SELECT DISTINCT NULL +UNION +SELECT CAST( 1 AS BIT) AS Col1 +GO +~~START~~ +bit +1 + +~~END~~ + + +SELECT DISTINCT 'longer string' +UNION +SELECT CAST('bar' as VARCHAR(3)) +GO +~~START~~ +varchar +bar +longer string +~~END~~ + + +CREATE TABLE babel1874 (a CHAR(3), b NVARCHAR(MAX), c BIT) +GO + +INSERT INTO babel1874 VALUES ('foo', N'ΘЖऌฒ', 1) +GO +~~ROW COUNT: 1~~ + + +SELECT N'longer string' as c1, CAST('1' AS VARCHAR(10)) as c2, c as c3 FROM babel1874 +UNION +SELECT a, COUNT(b), NULL as c3 FROM babel1874 GROUP BY a, c3 +ORDER BY c3, c2, c1 +GO +~~START~~ +nvarchar#!#int#!#bit +foo#!#1#!# +longer string#!#1#!#1 +~~END~~ + + +DROP TABLE babel1874 +GO + +CREATE TABLE babel3392_collation(c1 NVARCHAR(20) COLLATE japanese_cs_as, c2 NCHAR(10) COLLATE japanese_cs_as); +GO + +INSERT INTO babel3392_collation VALUES ('ã†', 'ï½³') +go +~~ROW COUNT: 1~~ + + +SELECT * FROM babel3392_collation +GO +~~START~~ +nvarchar#!#nchar +ã†#!#ï½³ +~~END~~ + + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT c1 as babel4157_c1 FROM babel3392_collation + UNION + SELECT c2 as babel4157_c1 FROM babel3392_collation +) tbl +GO + +SELECT * FROM babel4157_tbl order by babel4157_c1 COLLATE japanese_cs_as +GO +~~START~~ +nvarchar +ㆠ+ï½³ +~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT c1 as babel4157_c1 FROM babel3392_collation + UNION + SELECT 'foo' as babel4157_c1 +) tbl +GO + +SELECT * FROM babel4157_tbl order by babel4157_c1 COLLATE SQL_Latin1_General_CP1_CI_AS +GO +~~START~~ +nvarchar +foo +ㆠ+~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#40 +~~END~~ + + +DROP TABLE babel4157_tbl +GO + +CREATE TABLE babel3392_nocol(c1 VARCHAR(30)) +GO + +INSERT INTO babel3392_nocol VALUES('foo') +GO +~~ROW COUNT: 1~~ + + +SELECT tbl.babel4157_c1 INTO babel4157_tbl FROM ( + SELECT c1 as babel4157_c1 FROM babel3392_nocol + UNION + SELECT c1 as babel4157_c1 FROM babel3392_collation +) tbl +GO + +SELECT * FROM babel4157_tbl order by babel4157_c1 COLLATE SQL_Latin1_General_CP1_CI_AS +GO +~~START~~ +nvarchar +foo +ㆠ+~~END~~ + + +SELECT name, max_length FROM sys.columns WHERE name = 'babel4157_c1' +GO +~~START~~ +varchar#!#smallint +babel4157_c1#!#60 +~~END~~ + + +DROP TABLE babel4157_tbl +GO +DROP TABLE babel3392_nocol +DROP TABLE babel3392_collation +GO 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-3474-vu-verify.out b/test/JDBC/expected/BABEL-3474-vu-verify.out index 7909190f81..17a5ee899f 100644 --- a/test/JDBC/expected/BABEL-3474-vu-verify.out +++ b/test/JDBC/expected/BABEL-3474-vu-verify.out @@ -30,7 +30,7 @@ GO SELECT * FROM BABEL_3474_vu_prepare_v4 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart microsecond is not supported by date function dateadd for data type datetime.)~~ @@ -39,7 +39,7 @@ GO SELECT * FROM BABEL_3474_vu_prepare_v5 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart microsecond is not supported by date function dateadd for data type smalldatetime.)~~ @@ -78,7 +78,7 @@ GO SELECT * FROM BABEL_3474_vu_prepare_v9 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart nanosecond is not supported by date function dateadd for data type datetime.)~~ @@ -87,7 +87,7 @@ GO SELECT * FROM BABEL_3474_vu_prepare_v10 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart nanosecond is not supported by date function dateadd for data type smalldatetime.)~~ @@ -96,7 +96,7 @@ GO SELECT * FROM BABEL_3474_vu_prepare_v11 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart day is not supported by date function dateadd for data type time.)~~ @@ -105,7 +105,7 @@ GO SELECT * FROM BABEL_3474_vu_prepare_v12 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart second is not supported by date function dateadd for data type date.)~~ @@ -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 @@ -164,7 +164,7 @@ GO EXEC BABEL_3474_vu_prepare_p4 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart microsecond is not supported by date function dateadd for data type datetime.)~~ @@ -173,7 +173,7 @@ GO EXEC BABEL_3474_vu_prepare_p5 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart microsecond is not supported by date function dateadd for data type smalldatetime.)~~ @@ -212,7 +212,7 @@ GO EXEC BABEL_3474_vu_prepare_p9 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart nanosecond is not supported by date function dateadd for data type datetime.)~~ @@ -221,7 +221,7 @@ GO EXEC BABEL_3474_vu_prepare_p10 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart nanosecond is not supported by date function dateadd for data type smalldatetime.)~~ @@ -230,7 +230,7 @@ GO EXEC BABEL_3474_vu_prepare_p11 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart day is not supported by date function dateadd for data type time.)~~ @@ -239,7 +239,7 @@ GO EXEC BABEL_3474_vu_prepare_p12 GO -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart second is not supported by date function dateadd for data type date.)~~ @@ -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 @@ -300,7 +300,7 @@ SELECT BABEL_3474_vu_prepare_f4() GO ~~START~~ datetime -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart microsecond is not supported by date function dateadd for data type datetime.)~~ @@ -311,7 +311,7 @@ SELECT BABEL_3474_vu_prepare_f5() GO ~~START~~ smalldatetime -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart microsecond is not supported by date function dateadd for data type smalldatetime.)~~ @@ -352,7 +352,7 @@ SELECT BABEL_3474_vu_prepare_f9() GO ~~START~~ datetime -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart nanosecond is not supported by date function dateadd for data type datetime.)~~ @@ -363,7 +363,7 @@ SELECT BABEL_3474_vu_prepare_f10() GO ~~START~~ smalldatetime -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart nanosecond is not supported by date function dateadd for data type smalldatetime.)~~ @@ -374,7 +374,7 @@ SELECT BABEL_3474_vu_prepare_f11() GO ~~START~~ time -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart day is not supported by date function dateadd for data type time.)~~ @@ -385,7 +385,7 @@ SELECT BABEL_3474_vu_prepare_f12() GO ~~START~~ date -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 9810)~~ ~~ERROR (Message: The datepart second is not supported by date function dateadd for data type date.)~~ @@ -396,7 +396,7 @@ SELECT BABEL_3474_vu_prepare_f13() GO ~~START~~ date -2016-12-26 +2016-12-27 ~~END~~ DROP FUNCTION BABEL_3474_vu_prepare_f13 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/expected/BABEL-3512.out b/test/JDBC/expected/BABEL-3512.out index 137f74e0e5..0089073436 100644 --- a/test/JDBC/expected/BABEL-3512.out +++ b/test/JDBC/expected/BABEL-3512.out @@ -285,6 +285,7 @@ WITH/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a1 SET babelfish_showplan_all ON GO +-- the purpose of babel_3512_t2_cte is to check the behavior for invalid hint EXEC babel_3512_proc_6 GO ~~START~~ @@ -295,8 +296,11 @@ Query Text: EXEC babel_3512_proc_6 Index Cond: (b1 = 1) Filter: (c1 = 1) Query Text: WITH/*+ indexscan(babel_3512_t2 index_babel_3512_t2_b1babel_351ed65eb34ef55dec01b20e7fff9c5ca06) */ babel_3512_t2_cte (a1, b2, c2) as (SELECT * FROM babel_3512_t2 WHERE b2 = 1) SELECT * FROM babel_3512_t2_cte WHERE c2 = 1 - -> Seq Scan on babel_3512_t2 - Filter: ((b2 = 1) AND (c2 = 1)) + -> Bitmap Heap Scan on babel_3512_t2 + Recheck Cond: (b2 = 1) + Filter: (c2 = 1) + -> Bitmap Index Scan on index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 + Index Cond: (b2 = 1) ~~END~~ diff --git a/test/JDBC/expected/BABEL-3513-vu-verify.out b/test/JDBC/expected/BABEL-3513-vu-verify.out index 3ada2def4c..df55115062 100644 --- a/test/JDBC/expected/BABEL-3513-vu-verify.out +++ b/test/JDBC/expected/BABEL-3513-vu-verify.out @@ -6,6 +6,9 @@ analyze master_dbo.babel_3513_t2; go -- tsql +exec sp_babelfish_configure 'enable_pg_hint', 'on', 'server' +go + SELECT set_config('babelfishpg_tsql.explain_costs', 'off', false) GO ~~START~~ 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-3637.out b/test/JDBC/expected/BABEL-3637.out index 68946e84b6..d54eb0d3ba 100644 --- a/test/JDBC/expected/BABEL-3637.out +++ b/test/JDBC/expected/BABEL-3637.out @@ -43,7 +43,7 @@ GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -92,7 +92,7 @@ GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -117,7 +117,7 @@ GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -140,7 +140,7 @@ GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -162,7 +162,7 @@ GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -190,7 +190,7 @@ GO varchar#!#varchar#!#varchar#!#varchar#!#varchar babel_3637_login2#!#public#!#babel_3637_login2#!#master#!#dbo dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -219,7 +219,7 @@ GO varchar#!#varchar#!#varchar#!#varchar#!#varchar babel_3637_login2#!#public#!#babel_3637_login2#!#master#!#dbo dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -243,7 +243,7 @@ GO varchar#!#varchar#!#varchar#!#varchar#!#varchar babel_3637_login2#!#public#!#babel_3637_login2#!#master#!#dbo dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ @@ -267,7 +267,7 @@ GO varchar#!#varchar#!#varchar#!#varchar#!#varchar babel_3637_login2#!#public#!#babel_3637_login2#!#master#!#dbo dbo#!#db_owner#!#jdbc_user#!##!#dbo -guest#!#public#!##!##!# +guest#!#public#!##!##!#guest ~~END~~ diff --git a/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-vu-cleanup.out b/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-vu-cleanup.out new file mode 100644 index 0000000000..a23e01a771 --- /dev/null +++ b/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-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-before-14_10-or-15_5-vu-prepare.out b/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-vu-prepare.out new file mode 100644 index 0000000000..41fef7608b --- /dev/null +++ b/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-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-before-14_10-or-15_5-vu-verify.out b/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-vu-verify.out new file mode 100644 index 0000000000..9aaf10c9dd --- /dev/null +++ b/test/JDBC/expected/BABEL-3696-before-14_10-or-15_5-vu-verify.out @@ -0,0 +1,87 @@ +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/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..035edd1a4b --- /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/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-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..d4a41430b4 --- /dev/null +++ b/test/JDBC/expected/BABEL-3725-vu-verify.out @@ -0,0 +1,70 @@ +-- tsql +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 + +-- psql +create table psql_limit_dml(a INT); +-- Is allowed with insert +insert into psql_limit_dml values (1), (2), (3) limit 2; +select * from psql_limit_dml; +go +~~ROW COUNT: 2~~ + +~~START~~ +int4 +1 +2 +~~END~~ + + +-- Not allowed with update / delete +update psql_limit_dml set a = 100 limit 1; +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: syntax error at or near "limit" + Position: 71 + Server SQLState: 42601)~~ + +update psql_limit_dml set a = 100 where a = 1; +select * from psql_limit_dml; +go +~~ROW COUNT: 1~~ + +~~START~~ +int4 +2 +100 +~~END~~ + + +delete from psql_limit_dml where psql_limit_dml.a = 2 limit 1; +go +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: syntax error at or near "limit" + Position: 55 + Server SQLState: 42601)~~ + +delete from psql_limit_dml where psql_limit_dml.a = 2; +select * from psql_limit_dml +go +~~ROW COUNT: 1~~ + +~~START~~ +int4 +100 +~~END~~ + + +drop table psql_limit_dml; +go diff --git a/test/JDBC/expected/BABEL-3802-vu-cleanup.out b/test/JDBC/expected/BABEL-3802-vu-cleanup.out index 8ae85e0466..480b21ab59 100644 --- a/test/JDBC/expected/BABEL-3802-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-3802-vu-cleanup.out @@ -25,12 +25,78 @@ GO DROP PROCEDURE BABEL_3802_vu_prepare_t_p5 GO +DROP PROCEDURE BABEL_3802_vu_prepare_t_p8 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p9 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p10 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p11 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p12 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p13 +GO + DROP PROCEDURE BABEL_3802_vu_prepare_t_p6 GO +DROP PROCEDURE BABEL_3802_vu_prepare_t_p14 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p15 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p16 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p17 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p18 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p19 +GO + DROP PROCEDURE BABEL_3802_vu_prepare_t_p7 GO +DROP PROCEDURE BABEL_3802_vu_prepare_t_p20 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p21 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p22 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p23 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p24 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p25 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p26 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p27 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p28 +GO + +DROP PROCEDURE BABEL_3802_vu_prepare_t_p29 +GO + DROP VIEW BABEL_3802_vu_prepare_t_v8 GO @@ -45,3 +111,78 @@ GO DROP VIEW BABEL_3802_vu_prepare_t_v4 GO + +DROP VIEW BABEL_3802_vu_prepare_t_v5 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v6 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v7 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v9 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v10 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v11 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v12 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v13 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v14 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v15 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v16 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v17 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v18 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v19 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v20 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v21 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v22 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v23 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v24 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v25 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v26 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v27 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v28 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v29 +GO + +DROP VIEW BABEL_3802_vu_prepare_t_v30 +GO diff --git a/test/JDBC/expected/BABEL-3802-vu-prepare.out b/test/JDBC/expected/BABEL-3802-vu-prepare.out index 90a3b9132e..cdc56f156d 100644 --- a/test/JDBC/expected/BABEL-3802-vu-prepare.out +++ b/test/JDBC/expected/BABEL-3802-vu-prepare.out @@ -41,7 +41,18 @@ CREATE PROCEDURE BABEL_3802_vu_prepare_t_p1 AS ( power(CAST(NULL AS BIGINT),1), power(CAST(8969.32 AS BIGINT),1), power(CAST(896932 AS BIGINT),1.1), - power(CAST(896932 AS BIGINT),1.2) + power(CAST(896932 AS BIGINT),1.2), + power(CAST(NULL AS BIGINT),NULL), + power(CAST(896932 AS BIGINT),NULL), + power(CAST(2 AS BIGINT), -1), + power(CAST(0 AS BIGINT),0), + power(CAST(-2 AS BIGINT),-1), + power(CAST(2 AS BIGINT),-0.2), + power(CAST(-922 AS BIGINT),NULL), + power(CAST(-922 AS BIGINT),0), + power(CAST(NULL AS BIGINT),-100), + power(CAST(NULL AS BIGINT),0), + power(CAST(-8969.32 AS BIGINT),1) ); GO @@ -52,7 +63,18 @@ CREATE PROCEDURE BABEL_3802_vu_prepare_t_p2 AS ( power(CAST(NULL AS INT),1), power(CAST(8969.32 AS INT),1), power(CAST(896932 AS INT),1.1), - power(CAST(896932 AS INT),1.2) + power(CAST(896932 AS INT),1.2), + power(CAST(NULL as INT),NULL), + power(CAST(8963 as INT),NULL), + power(CAST(2 AS INT), -1), + power(CAST(0 AS INT),0), + power(CAST(-2 AS INT),-1), + power(CAST(2 AS INT),-0.2), + power(CAST(-922 AS INT),NULL), + power(CAST(-922 AS INT),0), + power(CAST(NULL AS INT),-10), + power(CAST(NULL AS INT),0), + power(CAST(-8969.32 AS INT),1) ); GO @@ -63,7 +85,19 @@ CREATE PROCEDURE BABEL_3802_vu_prepare_t_p3 AS ( power(CAST(NULL AS SMALLINT),1), power(CAST(8969.32 AS SMALLINT),1), power(CAST(8962 AS SMALLINT),1.1), - power(CAST(8962 AS SMALLINT),1.2) + power(CAST(8962 AS SMALLINT),1.2), + power(CAST(NULL AS SMALLINT),NULL), + power(CAST(8962 AS SMALLINT),NULL), + power(CAST(100 AS SMALLINT),3), + power(CAST(2 AS SMALLINT), -1), + power(CAST(0 AS SMALLINT),0), + power(CAST(-2 AS SMALLINT),-1), + power(CAST(2 AS SMALLINT),-0.2), + power(CAST(-922 AS SMALLINT),NULL), + power(CAST(-922 AS SMALLINT),0), + power(CAST(NULL AS SMALLINT),-10), + power(CAST(NULL AS SMALLINT),0), + power(CAST(-8969.32 AS SMALLINT),1) ); GO @@ -74,7 +108,15 @@ CREATE PROCEDURE BABEL_3802_vu_prepare_t_p4 AS ( power(CAST(NULL AS TINYINT),1), power(CAST(100.32 AS TINYINT),1), power(CAST(100 AS TINYINT),1.1), - power(CAST(100 AS TINYINT),1.2) + power(CAST(100 AS TINYINT),1.2), + power(CAST(NULL AS TINYINT),NULL), + power(CAST(100 AS TINYINT),NULL), + power(CAST(100 AS TINYINT),3), + power(CAST(2 AS TINYINT), -1), + power(CAST(0 AS TINYINT),0), + power(CAST(2 AS TINYINT),-0.2), + power(CAST(NULL AS TINYINT),-10), + power(CAST(NULL AS TINYINT),0) ); GO @@ -83,14 +125,82 @@ GO CREATE PROCEDURE BABEL_3802_vu_prepare_t_p5 AS (SELECT power(CAST(-9223372036854775808 AS BIGINT),2)); GO +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p8 AS (SELECT power(CAST(9223372036854775807 AS BIGINT),2)); +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p9 AS (SELECT power(CAST(9223372036854775808 AS BIGINT),1)); +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p10 AS (SELECT power(CAST(-9223372036854775809 AS BIGINT),1)); +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p11 AS (SELECT power(CAST(-922337203685477580 AS BIGINT),1.1)); +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p12 AS (SELECT power(CAST(-922337203685477580 AS BIGINT),-1.1)); +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p13 AS (SELECT power(CAST(0 AS BIGINT),-1)); +GO + ----Trigger Int Error CREATE PROCEDURE BABEL_3802_vu_prepare_t_p6 AS SELECT power(CAST(-2147483648 AS INT),2) GO +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p14 AS SELECT power(CAST(2147483648 AS INT),1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p15 AS SELECT power(CAST(-2147483649 AS INT),1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p16 AS SELECT power(CAST(2147483647 AS INT),2) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p17 AS SELECT power(CAST(-214748364 AS INT),1.1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p18 AS SELECT power(CAST(-214748364 AS INT),-1.1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p19 AS SELECT power(CAST(0 AS INT),-1) +GO + ----Trigger SmallInt Error CREATE PROCEDURE BABEL_3802_vu_prepare_t_p7 AS SELECT power(CAST(-32768 AS SMALLINT),3) GO +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p20 AS SELECT power(CAST(32768 AS SMALLINT),1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p21 AS SELECT power(CAST(32767 AS SMALLINT),4) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p22 AS SELECT power(CAST(-32769 AS SMALLINT),1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p23 AS SELECT power(CAST(-3276 AS SMALLINT),1.1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p24 AS SELECT power(CAST(-3276 AS SMALLINT),-1.1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p25 AS SELECT power(CAST(0 AS SMALLINT),-1) +GO + + +---Trigger TinyInt Error +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p26 AS SELECT power(CAST(-1 AS TINYINT),1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p27 AS SELECT power(CAST(255 AS TINYINT),5) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p28 AS SELECT power(CAST(256 AS TINYINT),1) +GO + +CREATE PROCEDURE BABEL_3802_vu_prepare_t_p29 AS SELECT power(CAST(0 AS TINYINT),-1) +GO + CREATE VIEW BABEL_3802_vu_prepare_t_v8 AS SELECT power(CAST(1 AS TINYINT),1.1) GO @@ -101,7 +211,18 @@ CREATE VIEW BABEL_3802_vu_prepare_t_v1 AS ( power(CAST(NULL AS BIGINT),1) AS res3, power(CAST(8969.32 AS BIGINT),1) AS res4, power(CAST(896932 AS BIGINT),1.1) AS res5, - power(CAST(896932 AS BIGINT),1.2) AS res6 + power(CAST(896932 AS BIGINT),1.2) AS res6, + power(CAST(NULL AS BIGINT),NULL) AS res7, + power(CAST(896932 AS BIGINT),NULL) AS res8, + power(CAST(2 AS BIGINT), -1) AS res9, + power(CAST(0 AS BIGINT),0) AS res10, + power(CAST(-2 AS BIGINT),-1) AS res11, + power(CAST(2 AS BIGINT),-0.2) AS res12, + power(CAST(-922 AS BIGINT),NULL) AS res13, + power(CAST(-922 AS BIGINT),0) AS res14, + power(CAST(NULL AS BIGINT),-100) AS res15, + power(CAST(NULL AS BIGINT),0) AS res16, + power(CAST(-8969.32 AS BIGINT),1) AS res17 ); GO @@ -112,7 +233,18 @@ CREATE VIEW BABEL_3802_vu_prepare_t_v2 AS ( power(CAST(NULL AS INT),1) AS res3, power(CAST(8969.32 AS INT),1) AS res4, power(CAST(896932 AS INT),1.1) AS res5, - power(CAST(896932 AS INT),1.2) AS res6 + power(CAST(896932 AS INT),1.2) AS res6, + power(CAST(NULL as INT),NULL) AS res7, + power(CAST(8963 as INT),NULL) AS res8, + power(CAST(2 AS INT), -1) AS res9, + power(CAST(0 AS INT),0) AS res10, + power(CAST(-2 AS INT),-1) AS res11, + power(CAST(2 AS INT),-0.2) AS res12, + power(CAST(-922 AS INT),NULL) AS res13, + power(CAST(-922 AS INT),0) AS res14, + power(CAST(NULL AS INT),-10) AS res15, + power(CAST(NULL AS INT),0) AS res16, + power(CAST(-8969.32 AS INT),1) AS res17 ); GO @@ -123,7 +255,19 @@ CREATE VIEW BABEL_3802_vu_prepare_t_v3 AS ( power(CAST(NULL AS SMALLINT),1) AS res3, power(CAST(899.32 AS SMALLINT),1) AS res4, power(CAST(8962 AS SMALLINT),1.1) AS res5, - power(CAST(896 AS SMALLINT),1.2) AS res6 + power(CAST(896 AS SMALLINT),1.2) AS res6, + power(CAST(NULL AS SMALLINT),NULL) AS res7, + power(CAST(8962 AS SMALLINT),NULL) AS res8, + power(CAST(100 AS SMALLINT),3) AS res9, + power(CAST(2 AS SMALLINT), -1) AS res10, + power(CAST(0 AS SMALLINT),0) AS res11, + power(CAST(-2 AS SMALLINT),-1)AS res12, + power(CAST(2 AS SMALLINT),-0.2) AS res13, + power(CAST(-922 AS SMALLINT),NULL) AS res14, + power(CAST(-922 AS SMALLINT),0) AS res15, + power(CAST(NULL AS SMALLINT),-10) AS res16, + power(CAST(NULL AS SMALLINT),0) AS res17, + power(CAST(-8969.32 AS SMALLINT),1) AS res18 ); GO @@ -134,6 +278,95 @@ CREATE VIEW BABEL_3802_vu_prepare_t_v4 AS ( power(CAST(NULL AS TINYINT),1) AS res3, power(CAST(89.32 AS TINYINT),1) AS res4, power(CAST(100 AS TINYINT),1.1) AS res5, - power(CAST(100 AS TINYINT),1.2) AS res6 + power(CAST(100 AS TINYINT),1.2) AS res6, + power(CAST(NULL AS TINYINT),NULL) AS res7, + power(CAST(100 AS TINYINT),NULL) AS res8, + power(CAST(100 AS TINYINT),3) AS res9, + power(CAST(2 AS TINYINT), -1) AS res10, + power(CAST(0 AS TINYINT),0) AS res11, + power(CAST(2 AS TINYINT),-0.2) AS res12, + power(CAST(NULL AS TINYINT),-10) AS res13, + power(CAST(NULL AS TINYINT),0) AS res14 ); GO + + +--Trigger BigInt Error +CREATE VIEW BABEL_3802_vu_prepare_t_v5 AS ( SELECT power(CAST(-9223372036854775808 AS BIGINT),2) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v6 AS ( SELECT power(CAST(9223372036854775807 AS BIGINT),2) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v7 AS ( SELECT power(CAST(9223372036854775808 AS BIGINT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v9 AS ( SELECT power(CAST(-9223372036854775809 AS BIGINT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v10 AS (SELECT power(CAST(-922337203685477580 AS BIGINT),1.1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v11 AS (SELECT power(CAST(-922337203685477580 AS BIGINT),-1.1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v12 AS (SELECT power(CAST(0 AS BIGINT),-1) AS res1); +GO + +--Trigger Int Error +CREATE VIEW BABEL_3802_vu_prepare_t_v13 AS ( SELECT power(CAST(-2147483648 AS INT),2) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v14 AS ( SELECT power(CAST(2147483648 AS INT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v15 AS ( SELECT power(CAST(-2147483649 AS INT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v16 AS ( SELECT power(CAST(2147483647 AS INT),2) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v17 AS ( SELECT power(CAST(-214748364 AS INT),1.1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v18 AS ( SELECT power(CAST(-214748364 AS INT),-1.1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v19 AS ( SELECT power(CAST(0 AS INT),-1) AS res1); +GO + +--Trigger Small Int Error +CREATE VIEW BABEL_3802_vu_prepare_t_v20 AS ( SELECT power(CAST(-32768 AS SMALLINT),3) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v21 AS ( SELECT power(CAST(32768 AS SMALLINT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v22 AS ( SELECT power(CAST(32767 AS SMALLINT),4) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v23 AS ( SELECT power(CAST(-32769 AS SMALLINT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v24 AS ( SELECT power(CAST(-3276 AS SMALLINT),1.1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v25 AS ( SELECT power(CAST(-3276 AS SMALLINT),-1.1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v26 AS ( SELECT power(CAST(0 AS SMALLINT),-1) AS res1); +GO + + +--Trigger Tiny Int Error +CREATE VIEW BABEL_3802_vu_prepare_t_v27 AS ( SELECT power(CAST(-1 AS TINYINT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v28 AS ( SELECT power(CAST(255 AS TINYINT),5) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v29 AS ( SELECT power(CAST(256 AS TINYINT),1) AS res1); +GO + +CREATE VIEW BABEL_3802_vu_prepare_t_v30 AS ( SELECT power(CAST(0 AS TINYINT),-1) AS res1); +GO diff --git a/test/JDBC/expected/BABEL-3802-vu-verify.out b/test/JDBC/expected/BABEL-3802-vu-verify.out index 76df7bfd69..2f76ea94d4 100644 --- a/test/JDBC/expected/BABEL-3802-vu-verify.out +++ b/test/JDBC/expected/BABEL-3802-vu-verify.out @@ -2,8 +2,8 @@ SELECT power(a,b), power(b,b), power(c,b), power(d,b), power(e,b) from BABEL_380 GO ~~START~~ int#!#numeric#!#bigint#!#int#!#int +#!#1.00000000#!##!##!# -2147483648#!#1.00000000#!#-9223372036854775808#!#-32768#!#0 -0#!#1.00000000#!#0#!#0#!#0 101#!#1.00000000#!#97777#!#376#!#120 2147483647#!#1.00000000#!#9223372036854#!#32767#!#255 ~~END~~ @@ -36,31 +36,32 @@ int EXECUTE BABEL_3802_vu_prepare_t_p1 GO ~~START~~ -bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint --9223372036854775808#!#9223372036854#!#0#!#8969#!#3532120#!#13909497 +bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint +-9223372036854775808#!#9223372036854#!##!#8969#!#3532120#!#13909496#!##!##!#0#!#1#!#0#!#0#!##!#1#!##!##!#-8969 ~~END~~ EXECUTE BABEL_3802_vu_prepare_t_p2 GO ~~START~~ -int#!#int#!#int#!#int#!#int#!#int --2147483648#!#2147483647#!#0#!#8969#!#3532120#!#13909497 +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +-2147483648#!#2147483647#!##!#8969#!#3532120#!#13909496#!##!##!#0#!#1#!#0#!#0#!##!#1#!##!##!#-8969 ~~END~~ EXECUTE BABEL_3802_vu_prepare_t_p3 GO -~~ERROR (Code: 220)~~ - -~~ERROR (Message: smallint out of range)~~ +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +-32768#!#32767#!##!#8969#!#22266#!#55320#!##!##!#1000000#!#0#!#1#!#0#!#0#!##!#1#!##!##!#-8969 +~~END~~ EXECUTE BABEL_3802_vu_prepare_t_p4 GO ~~START~~ -int#!#int#!#int#!#int#!#int#!#int -0#!#255#!#0#!#100#!#158#!#251 +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +0#!#255#!##!#100#!#158#!#251#!##!##!#1000000#!#0#!#1#!#0#!##!# ~~END~~ @@ -71,6 +72,52 @@ GO ~~ERROR (Message: bigint out of range)~~ +EXECUTE BABEL_3802_vu_prepare_t_p8 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p9 +GO +~~START~~ +bigint +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p10 +GO +~~START~~ +bigint +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p11 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p12 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p13 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + EXECUTE BABEL_3802_vu_prepare_t_p6 GO ~~ERROR (Code: 8115)~~ @@ -78,13 +125,133 @@ GO ~~ERROR (Message: integer out of range)~~ +EXECUTE BABEL_3802_vu_prepare_t_p14 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p15 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p16 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p17 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p18 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p19 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + EXECUTE BABEL_3802_vu_prepare_t_p7 GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p20 +GO ~~ERROR (Code: 220)~~ ~~ERROR (Message: smallint out of range)~~ +EXECUTE BABEL_3802_vu_prepare_t_p21 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p22 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: smallint out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p23 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p24 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p25 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p26 +GO +~~START~~ +int +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p27 +GO +~~START~~ +int +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p28 +GO +~~START~~ +int +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + + +EXECUTE BABEL_3802_vu_prepare_t_p29 +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + SELECT * FROM BABEL_3802_vu_prepare_t_v8 GO ~~START~~ @@ -96,31 +263,218 @@ int SELECT * FROM BABEL_3802_vu_prepare_t_v1 GO ~~START~~ -bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint --9223372036854775808#!#9223372036854#!#0#!#8969#!#3532120#!#13909497 +bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint +-9223372036854775808#!#9223372036854#!##!#8969#!#3532120#!#13909496#!##!##!#0#!#1#!#0#!#0#!##!#1#!##!##!#-8969 ~~END~~ SELECT * FROM BABEL_3802_vu_prepare_t_v2 GO ~~START~~ -int#!#int#!#int#!#int#!#int#!#int --2147483648#!#2147483647#!#0#!#8969#!#3532120#!#13909497 +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +-2147483648#!#2147483647#!##!#8969#!#3532120#!#13909496#!##!##!#0#!#1#!#0#!#0#!##!#1#!##!##!#-8969 ~~END~~ SELECT * FROM BABEL_3802_vu_prepare_t_v3 GO ~~START~~ -int#!#int#!#int#!#int#!#int#!#int --32768#!#32767#!#0#!#899#!#22266#!#3490 +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +-32768#!#32767#!##!#899#!#22266#!#3489#!##!##!#1000000#!#0#!#1#!#0#!#0#!##!#1#!##!##!#-8969 ~~END~~ SELECT * FROM BABEL_3802_vu_prepare_t_v4 GO ~~START~~ -int#!#int#!#int#!#int#!#int#!#int -0#!#255#!#0#!#89#!#158#!#251 +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +0#!#255#!##!#89#!#158#!#251#!##!##!#1000000#!#0#!#1#!#0#!##!# ~~END~~ + +SELECT * FROM BABEL_3802_vu_prepare_t_v5 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v6 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v7 +GO +~~START~~ +bigint +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v9 +GO +~~START~~ +bigint +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: bigint out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v10 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v11 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v12 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v13 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v14 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v15 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v16 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v17 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v18 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v19 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v20 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v21 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: smallint out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v22 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v23 +GO +~~ERROR (Code: 220)~~ + +~~ERROR (Message: smallint out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v24 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v25 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a negative number raised to a non-integer power yields a complex result)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v26 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v27 +GO +~~START~~ +int +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v28 +GO +~~START~~ +int +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v29 +GO +~~START~~ +int +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + + +SELECT * FROM BABEL_3802_vu_prepare_t_v30 +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: zero raised to a negative power is undefined)~~ + 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/expected/BABEL-3865.out b/test/JDBC/expected/BABEL-3865.out new file mode 100644 index 0000000000..a9731625c8 --- /dev/null +++ b/test/JDBC/expected/BABEL-3865.out @@ -0,0 +1,143 @@ +/* Test a variety of normal/pg datatypes */ +CREATE TABLE #temp_1( + a int, + b date, + c varchar, + d text, + e json, + f xml +) +GO + +/* Test a variety of babelfish-specific datatypes */ +CREATE TABLE #temp_2( + a sysname, + b datetime, + c datetime2, + d nchar, + e nvarchar, + f varbinary, + g numeric, + h smallmoney, + i money +) +GO + +/* Test user-created datatypes */ +CREATE TYPE typa FROM int +GO + +CREATE TYPE typb FROM nvarchar(100) +GO + +CREATE TABLE #temp_3( + a typa, + b typb +) +GO + +DROP TYPE typb +GO +~~ERROR (Code: 3732)~~ + +~~ERROR (Message: cannot drop type typb because other objects depend on it)~~ + + +DROP TYPE typa +GO +~~ERROR (Code: 3732)~~ + +~~ERROR (Message: cannot drop type typa because other objects depend on it)~~ + + +DROP TABLE #temp_3 +DROP TYPE typb +GO + +DROP TYPE typa +GO + +/* Test computed columns */ +CREATE TABLE #temp_3_5( + a int, + b as a + 1) +GO + +INSERT INTO #temp_3_5(a) VALUES (1) +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM #temp_3_5 +GO +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +DROP TABLE #temp_3_5 +GO + + +/* Test SELECT INTO */ +CREATE TYPE typc FROM nchar +GO + +CREATE TABLE tab_1 (a int, b typc) +GO + +INSERT INTO tab_1 VALUES (1, 'a') +GO +~~ROW COUNT: 1~~ + + +SELECT * INTO #temp_4 FROM tab_1 +GO + +SELECT * FROM #temp_4 +GO +~~START~~ +int#!#nchar +1#!#a +~~END~~ + + +DROP TYPE typc +GO +~~ERROR (Code: 3732)~~ + +~~ERROR (Message: cannot drop type typc because other objects depend on it)~~ + + +DROP TABLE tab_1 +GO + +DROP TABLE #temp_4 +GO + +DROP TYPE typc +GO + +/* Test Ownership + Roles, for pg_shdepend */ +CREATE ROLE role_a +GO + +CREATE TABLE #temp_5 (a int) +GO + +GRANT ALL ON #temp_5 TO role_a +GO + +DROP ROLE role_a +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: role "master_role_a" cannot be dropped because some objects depend on it)~~ + + +DROP TABLE #temp_5 +GO + +DROP ROLE role_a +GO diff --git a/test/JDBC/expected/BABEL-388.out b/test/JDBC/expected/BABEL-388.out index d73bf1190a..6fec2c5f87 100644 --- a/test/JDBC/expected/BABEL-388.out +++ b/test/JDBC/expected/BABEL-388.out @@ -79,8 +79,8 @@ select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v8; GO ~~START~~ varchar -text -text +"varchar" +"varchar" ~~END~~ @@ -90,8 +90,8 @@ select cast(pg_typeof(a) as varchar(10)) as typname from babel_388_v9; GO ~~START~~ varchar -text -text +"varchar" +"varchar" ~~END~~ diff --git a/test/JDBC/expected/BABEL-3943.out b/test/JDBC/expected/BABEL-3943.out index ceea96e0c0..7210ff5444 100644 --- a/test/JDBC/expected/BABEL-3943.out +++ b/test/JDBC/expected/BABEL-3943.out @@ -16,15 +16,35 @@ GO -- tsql +-- TODO: Fix BABEL-4359 SELECT avg([owner_amounts].[tax]) FROM [owner_amounts] WHERE moment_id = 862 and ISNULL([owner_amounts].[active], 0) = 1 AND [owner_amounts].[tax] is not null GO ~~START~~ numeric -0E-8 +0.000000 ~~END~~ -SELECT sum([owner_amounts].[tax]) FROM [owner_amounts] WHERE moment_id = 862 and ISNULL([owner_amounts].[active], 0) = 1 AND [owner_amounts].[tax] is not null +-- TODO: Fix BABEL-4359 +SELECT avg([owner_amounts].[tax]) FROM [owner_amounts] WHERE moment_id = 862 and cast([owner_amounts].[active] as smallint) = 1 AND [owner_amounts].[tax] is not null +GO +~~START~~ +numeric +0.000000 +~~END~~ + + +-- TODO: Fix BABEL-4359 +SELECT TOP 1 [owner_amounts].[tax] FROM [owner_amounts] WHERE moment_id = 862 and cast([owner_amounts].[active] as smallint) = 1 +GO +~~START~~ +numeric +0.000000 +~~END~~ + + +-- TODO: Fix BABEL-4359 +SELECT avg([owner_amounts].[tax]) FROM [owner_amounts] WHERE moment_id = 862 and cast([owner_amounts].[active] as int) = 1 AND [owner_amounts].[tax] is not null GO ~~START~~ numeric @@ -32,6 +52,22 @@ numeric ~~END~~ +-- TODO: Fix BABEL-4359 +SELECT TOP 1 [owner_amounts].[tax] FROM [owner_amounts] WHERE moment_id = 862 and cast([owner_amounts].[active] as int) = 1 +GO +~~START~~ +numeric +0.000000 +~~END~~ + + +SELECT sum([owner_amounts].[tax]) FROM [owner_amounts] WHERE moment_id = 862 and ISNULL([owner_amounts].[active], 0) = 1 AND [owner_amounts].[tax] is not null +GO +~~START~~ +numeric +0.000000 +~~END~~ + --cleanup drop table owner_amounts diff --git a/test/JDBC/expected/BABEL-3952-vu-cleanup.out b/test/JDBC/expected/BABEL-3952-vu-cleanup.out new file mode 100644 index 0000000000..946029c41a --- /dev/null +++ b/test/JDBC/expected/BABEL-3952-vu-cleanup.out @@ -0,0 +1,164 @@ +DROP VIEW DATE_BUCKET_vu_prepare_v3 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v4 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v5 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v6 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v7 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v8 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v9 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v10 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v11 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v11_2 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v12 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v12_origin_IS_NULL +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v13 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v14 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v15 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v16 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v17 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v18 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v20 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v21 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v22 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v23 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v24 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_invalid_datepart +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v25 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v26 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v27 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v28 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v29 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v30 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v31 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v32 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v33 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v34 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v35 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v36 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v37 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v38 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v39 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v40 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v41 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v42 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v43 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v44 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v45 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v46 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v47 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v48 +GO + +DROP VIEW DATE_BUCKET_vu_prepare_v49 +GO + +DROP PROCEDURE BABEL_3952_vu_prepare_p1 +GO + +DROP PROCEDURE BABEL_3952_vu_prepare_p2 +GO + +DROP PROCEDURE BABEL_3952_vu_prepare_p3 +GO + +DROP FUNCTION BABEL_3952_vu_prepare_f1 +GO + +DROP FUNCTION BABEL_3952_vu_prepare_f2 +GO + +DROP FUNCTION BABEL_3952_vu_prepare_f3 +GO diff --git a/test/JDBC/expected/BABEL-3952-vu-prepare.out b/test/JDBC/expected/BABEL-3952-vu-prepare.out new file mode 100644 index 0000000000..e9ae92b369 --- /dev/null +++ b/test/JDBC/expected/BABEL-3952-vu-prepare.out @@ -0,0 +1,538 @@ +-- Test with invalid number argument +-- Should Throw Error - 'Invalid bucket width value passed to date_bucket function. Only positive values are allowed.' +CREATE VIEW DATE_BUCKET_vu_prepare_v3 AS ( + select + date_bucket(year, -2, cast('2020-01-01' as date)) as db1, + date_bucket(year, 0, cast('2020-01-01' as date)) as db2 + ); +GO +-- Should throw - Argument data type text is invalid for argument 3 of date_bucket function. +CREATE VIEW DATE_BUCKET_vu_prepare_v4 AS ( + select + date_bucket(year, -2, '2020-01-01') as db1, + date_bucket(year, 0, '2020-01-01') as db2 + ); +GO +-- Should Throw Error - 'Argument data type NULL is invalid for argument 3 of date_bucket function.' +CREATE VIEW DATE_BUCKET_vu_prepare_v5 AS ( + select + date_bucket(year, -2, null) as db, + date_bucket(year, 0, null) as db1 + ); +GO + +-- Test with null value for number argument +-- Should Throw Error - 'Argument data type NULL is invalid for argument 2 of date_bucket function.' +CREATE VIEW DATE_BUCKET_vu_prepare_v6 AS ( + select + date_bucket(year, null, cast('2020-01-01' as date)) as db1 + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_v7 AS ( + select + date_bucket(year, null, '2020-01-01') as db2 + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_v8 AS ( + select + date_bucket(year, null, null) as db2 + ); +GO + +-- Test with null or invalid datatype for date argument +-- Should Throw Error - 'Argument data type NULL is invalid for argument 3 of date_bucket function.' +CREATE VIEW DATE_BUCKET_vu_prepare_v9 AS ( + select + date_bucket(year, 1, null) as db1, + date_bucket(year, 2, null, '2020-01-01') as db2, + date_bucket(year, 2, null, cast('2020-01-01' as date)) as db3, + date_bucket(year, 1, null, null) as db4 + ); +GO +-- Should throw Error - Argument data type varchar is invalid for argument 3 of date_bucket function. +CREATE VIEW DATE_BUCKET_vu_prepare_v10 AS ( + select + date_bucket(year, 2, '2020-01-01') as db1, + date_bucket(year,2, '2020-01-01', cast('2020-01-01' as date)) as db2, + date_bucket(year, 2, '2020-01-01', '2020-01-01') as db3, + date_bucket(year, 2, '2020-01-01', 3242) as db4 + ); +GO +-- Should throw Error - Argument data type varchar is invalid for argument 3 of Date_Bucket function. +CREATE VIEW DATE_BUCKET_vu_prepare_v11 AS ( + select + date_bucket(year, 2, 432) as db1, + date_bucket(year,2, 643, cast('2020-01-01' as date)) as db2, + date_bucket(year, 2, 432, '2020-01-01') as db3, + date_bucket(year, 2, 947, 3242) as db4 + ); +GO + +CREATE VIEW DATE_BUCKET_vu_prepare_v11_2 AS ( + select + date_bucket(dayofyear, 2, 6473) as db + ); +GO + +-- Test with invalid origin date +-- Should throw - Argument data type integer is invalid for argument 4 of Date_Bucket function +CREATE VIEW DATE_BUCKET_vu_prepare_v12 AS ( + select + date_bucket(year, 2, cast('2020-01-01' as date), '2020-01-01') as db2, + date_bucket(year, 2, cast('2020-01-01' as date), 534) as db3, + date_bucket(year, 2, cast('2020-09-12' as date), cast('2005-09-12' as datetime)) as db4 + ); +GO +-- Should return valid date_bucket - 2023-01-01 +CREATE VIEW DATE_BUCKET_vu_prepare_v12_origin_IS_NULL AS ( + SELECT + date_bucket(year, 3, CAST('2023-03-24' as date), null) as db1 + ); +GO + +-- Test with upper/lower limit of every date/time datatype. +CREATE VIEW DATE_BUCKET_vu_prepare_v13 As ( + select + date_bucket(day, 1, cast('9999-12-31' as date), cast('0001-01-01' as date)) as db1, + date_bucket(day, 1, cast('0001-01-01' as date),cast('9999-12-31' as date)) as db2 + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_v14 As ( + select + date_bucket(day, 1, cast('9999-12-31 23:59:59.997' as datetime), cast('1753-01-01 00:00:00' as datetime)) as db1 + ); +GO +-- Should throw - data out of range for datetime +CREATE VIEW DATE_BUCKET_vu_prepare_v15 As ( + select + date_bucket(day, 1, cast('1753-01-01 00:00:00' as datetime), cast('9999-12-31 23:59:59.997' as datetime)) as db2 + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_v16 As ( + select + date_bucket(day, 1, cast('9999-12-31 23:59:59.9999999' as datetime2), cast('0001-01-01 00:00:00' as datetime2)) as db1 + ); +GO +-- Should throw - data out of range for datetime2 +CREATE VIEW DATE_BUCKET_vu_prepare_v17 As ( + select + date_bucket(day, 1, cast('0001-01-01 00:00:00' as datetime2), cast('9999-12-31 23:59:59.9999999' as datetime2)) as db1 + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_v18 As ( + select + date_bucket(day, 1, cast('9999-12-31 23:59:59.9999999 +14:00' as datetimeoffset), cast('0001-01-01 00:00:00 -14:00' as datetimeoffset)) as db1 + ); +GO + +CREATE VIEW DATE_BUCKET_vu_prepare_v20 As ( + select + date_bucket(day, 1, cast('2079-06-06' as smalldatetime), cast('1900-01-01' as smalldatetime)) as db1, + date_bucket(day, 1, cast('2079-06-06' as smalldatetime), cast('1900-01-01' as smalldatetime)) as db2 + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_v21 As ( + select + date_bucket(minute, 1, cast('23:59:59.999999' as time), cast('00:00:00.0000000' as time)) as db1, + date_bucket(minute, 1, cast('00:00:00.0000000' as time), cast('23:59:59.999999' as time)) as db2 + ); +GO + +-- test with time input with datepart IN (year, quarter, month, week, day) +-- Raise ERROR - The datepart 'year' is not supported by date function date_bucket for data type time. +CREATE VIEW DATE_BUCKET_vu_prepare_v22 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('23:58:59' AS TIME)) AS YEARS_BUCKET + ); +GO + +-- test with date input with datepart IN (hour, minute, second, millisecond) +-- Raise ERROR - The datepart 'hour' is not supported by date function date_bucket for data type date.' +CREATE VIEW DATE_BUCKET_vu_prepare_v23 AS ( + SELECT + DATE_BUCKET(hour, 2, CAST('2000-01-01' AS DATE)) AS HOURS_BUCKET + ); +GO + +-- test with un-supported datepart. +-- RAISE ERROR - The datepart nanosecond is not supported by date function date_bucket for data type datetime2. +CREATE VIEW DATE_BUCKET_vu_prepare_v24 AS ( + SELECT + DATE_BUCKET(nanosecond, 2, CAST('2000-01-01 12:32:12.123' AS DATETIME2)) AS nanosecond_BUCKET + ); +GO +CREATE VIEW DATE_BUCKET_vu_prepare_invalid_datepart AS ( + SELECT + DATE_BUCKET(dayofmonth, 2, CAST('2000-01-01 12:32:12.123' AS DATETIME2)) AS nanosecond_BUCKET + ); +GO + +-- test with number argument exceed range of positive int. +-- RAISE ERROR - Integer out of range +CREATE VIEW DATE_BUCKET_vu_prepare_v25 AS ( + SELECT + DATE_BUCKET(DAY, 2147483648, CAST('2020-04-30 00:00:00' as datetime2)) AS DAYS_BUCKET + ); +GO + +-- test with float type of number +CREATE VIEW DATE_BUCKET_vu_prepare_v26 AS ( + select + date_bucket(day, 2.5, CAST('2020-04-30 00:00:00' as datetime2)) as db1 +); +GO + +-- TEST WITH DATE TYPE INPUT +-- 1. without optional argument 'origin' +CREATE VIEW DATE_BUCKET_vu_prepare_v27 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01' AS DATE)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01' AS DATE)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01' AS DATE)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01' AS DATE)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01' AS DATE)) AS WEEKS_BUCKET + ); +GO +-- 2. with optional argument 'origin' < 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v28 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01' AS DATE), CAST('1905-09-12' AS DATE)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01' AS DATE), CAST('1905-09-12' AS DATE)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01' AS DATE), CAST('1905-09-12' AS DATE)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01' AS DATE), CAST('1905-09-12' AS DATE)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01' AS DATE), CAST('1905-09-12' AS DATE)) AS WEEKS_BUCKET + ); +GO +-- 3. with optional argument 'origin' > 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v29 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01' AS DATE), CAST('2010-09-21' AS DATE)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01' AS DATE), CAST('2010-09-21' AS DATE)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01' AS DATE), CAST('2010-09-21' AS DATE)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01' AS DATE), CAST('2010-09-21' AS DATE)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01' AS DATE), CAST('2010-09-21' AS DATE)) AS WEEKS_BUCKET + ); +GO + +-- TEST WITH DATETIME INPUT +-- 1. without optional argument 'origin' +CREATE VIEW DATE_BUCKET_vu_prepare_v30 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS MILLISECONDS_BUCKET + ); +GO +-- 2. with optional argument 'origin' < 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v31 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 23:30:05.523' AS DATETIME), CAST('1910-09-12 23:45:10.432' AS DATETIME)) AS MILLISECONDS_BUCKET + ); +GO +-- 3. with optional argument 'origin' > 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v32 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('1910-09-12 23:45:10.432' AS DATETIME), CAST('2000-01-01 23:30:05.523' AS DATETIME)) AS MILLISECONDS_BUCKET + ); +GO + +-- TEST WITH datetime2 input +-- 1. without optional argument 'origin' +CREATE VIEW DATE_BUCKET_vu_prepare_v33 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS MILLISECONDS_BUCKET + ); +GO +-- 2. with optional argument 'origin' < 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v34 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 23:30:05.523456' AS DATETIME2), CAST('1915-08-15 22:35:05.422456' AS DATETIME2)) AS MILLISECONDS_BUCKET + ); +GO +-- 3. with optional argument 'origin' > 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v35 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS MILLISECONDS_BUCKET + ); +GO + +-- 4. when millisecond trunc is required. +CREATE VIEW DATE_BUCKET_vu_prepare_v36 AS ( + SELECT + date_bucket(year, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS YEARS_BUCKET, + date_bucket(month, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2020-07-02 02:12:30.4467' as datetime2)) AS month_BUCKET, + date_bucket(quarter, 1, cast('2020-05-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS quarter_bucket, + date_bucket(week, 1, cast('2020-06-30 02:12:30.4463' as datetime2), cast('2019-07-02 02:12:30.4467' as datetime2)) AS week_BUCKET, + date_bucket(day, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS day_BUCKET, + date_bucket(hour, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS hour_BUCKET, + date_bucket(minute, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS minute_BUCKET, + date_bucket(second, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS second_BUCKET, + date_bucket(millisecond, 1, cast('2020-08-02 02:12:30.4463' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS millisecond_BUCKET1, + date_bucket(millisecond, 1, cast('2020-08-02 02:12:30.4443' as datetime2), cast('2019-08-02 02:12:30.4467' as datetime2)) AS millisecond_BUCKET2 + ); +GO + +-- TEST WITH datetimeoffset input +-- 1. without optional argument 'origin' +CREATE VIEW DATE_BUCKET_vu_prepare_v37 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 12:25:32 +02:00' AS DATETIMEOFFSET)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 12:25:32 +09:20' AS DATETIMEOFFSET)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 12:25:32 +13:10' AS DATETIMEOFFSET)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 12:25:32 +10:23' AS DATETIMEOFFSET)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 12:25:32 -10:32' AS DATETIMEOFFSET)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 12:25:32 +12:08' AS DATETIMEOFFSET)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 12:25:32 -08:10' AS DATETIMEOFFSET)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 12:25:32 +00:00' AS DATETIMEOFFSET)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 12:25:32 +11:00' AS DATETIMEOFFSET)) AS MILLISECONDS_BUCKET + ); +GO +-- 2. with optional argument 'origin' < 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v38 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 12:25:32 +02:12' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +02:12' AS DATETIMEOFFSET)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 12:25:32 +01:11' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +01:10' AS DATETIMEOFFSET)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 12:25:32 +04:10' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +03:15' AS DATETIMEOFFSET)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 12:25:32 -03:00' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +12:02' AS DATETIMEOFFSET)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 12:25:32 -05:02' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 -02:24' AS DATETIMEOFFSET)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 12:25:32 -01:05' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +03:29' AS DATETIMEOFFSET)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 12:25:32 +00:09' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 -06:45' AS DATETIMEOFFSET)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 12:25:32 +10:17' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +05:10' AS DATETIMEOFFSET)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 12:25:32 +07:20' AS DATETIMEOFFSET), CAST('1920-03-22 13:20:31 +12:32' AS DATETIMEOFFSET)) AS MILLISECONDS_BUCKET + ); +GO +-- 3. with optional argument 'origin' > 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v39 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('1920-03-22 13:20:31 +02:12' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 -01:05' AS DATETIMEOFFSET)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('1920-03-22 13:20:31 +01:10' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 -03:00' AS DATETIMEOFFSET)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('1920-03-22 13:20:31 +03:15' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 -05:02' AS DATETIMEOFFSET)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('1920-03-22 13:20:31 +12:02' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 +10:17' AS DATETIMEOFFSET)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('1920-03-22 13:20:31 -02:24' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 +01:11' AS DATETIMEOFFSET)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('1920-03-22 13:20:31 +03:29' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 -05:02' AS DATETIMEOFFSET)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('1920-03-22 13:20:31 -06:45' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 +04:10' AS DATETIMEOFFSET)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('1920-03-22 13:20:31 +05:10' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 +12:08' AS DATETIMEOFFSET)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('1920-03-22 13:20:31 +12:32' AS DATETIMEOFFSET), CAST('2000-01-01 12:25:32 +07:20' AS DATETIMEOFFSET)) AS MILLISECONDS_BUCKET + ); +GO +-- 4. when millisecond trunc is required. +CREATE VIEW DATE_BUCKET_vu_prepare_v40 AS ( + SELECT + date_bucket(year, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS YEARS_BUCKET, + date_bucket(month, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2020-07-02 02:12:30.4467 +00:00' as datetimeoffset)) AS month_BUCKET, + date_bucket(quarter, 1, cast('2020-05-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS quarter_bucket, + date_bucket(week, 1, cast('2020-06-30 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-07-02 02:12:30.4467 +00:00' as datetimeoffset)) AS week_BUCKET, + date_bucket(day, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS day_BUCKET, + date_bucket(hour, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS hour_BUCKET, + date_bucket(minute, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS minute_BUCKET, + date_bucket(second, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS second_BUCKET, + date_bucket(millisecond, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS millisecond_BUCKET1, + date_bucket(millisecond, 1, cast('2020-08-02 02:12:30.4443 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS millisecond_BUCKET2 + ); +GO + +-- TEST WITH smalldatetime input +-- 1. without optional argument 'origin' +CREATE VIEW DATE_BUCKET_vu_prepare_v41 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS MILLISECONDS_BUCKET + ); +GO +-- 2. with optional argument 'origin' < 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v42 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS MILLISECONDS_BUCKET + ); +GO +-- 3. with optional argument 'origin' > 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v43 AS ( + SELECT + DATE_BUCKET(year, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS YEARS_BUCKET, + DATE_BUCKET(quarter, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS QUARTER_BUCKET, + DATE_BUCKET(month, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS MONTHS_BUCKET, + DATE_BUCKET(day, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS DAYS_BUCKET, + DATE_BUCKET(week, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS WEEKS_BUCKET, + DATE_BUCKET(hour, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('1911-02-11 21:55:56' AS SMALLDATETIME), CAST('2000-01-01 23:58:59' AS SMALLDATETIME)) AS MILLISECONDS_BUCKET + ); +GO + +-- test with time input +-- postgresql support time datatype till 6 digits after decimal point. +-- select DATE_BUCKET(hour, 2, CAST('23:58:59.5464469' AS TIME), CAST('12:23:56.8463639' AS TIME)) AS HOURS_BUCKET output of this query will differ from SQL server at the last digit +-- SQL server output - 22:23:56.8463639 and babelfish output of T-sql endpoint = 22:23:56.8463640 +-- 1. Without optiona argument 'origin' +CREATE VIEW DATE_BUCKET_vu_prepare_v44 AS ( + SELECT + DATE_BUCKET(hour, 2, CAST('23:58:59' AS TIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('23:58:59' AS TIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('23:58:59' AS TIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('23:58:59' AS TIME)) AS MILLISECONDS_BUCKET + ); +GO +-- 2. With optional argument 'origin' < 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v45 AS ( + SELECT + DATE_BUCKET(hour, 2, CAST('23:58:59.546446' AS TIME), CAST('12:23:56.846363' AS TIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('23:58:59.546446' AS TIME), CAST('12:23:56.846363' AS TIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('23:58:59.546446' AS TIME), CAST('12:23:56.846363' AS TIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('23:58:59.546446' AS TIME), CAST('12:23:56.846363' AS TIME)) AS MILLISECONDS_BUCKET + ); +GO +-- 3. With optional argument 'origin' > 'date' +CREATE VIEW DATE_BUCKET_vu_prepare_v46 AS ( + SELECT + DATE_BUCKET(hour, 2, CAST('12:23:56.846363' AS TIME), CAST('23:58:59.546446' AS TIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 2, CAST('12:23:56.846363' AS TIME), CAST('23:58:59.546446' AS TIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 2, CAST('12:23:56.846363' AS TIME), CAST('23:58:59.546446' AS TIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 2, CAST('12:23:56.846363' AS TIME), CAST('23:58:59.546446' AS TIME)) AS MILLISECONDS_BUCKET + ); +GO + +-- 4. Test when trunc is required +CREATE VIEW DATE_BUCKET_vu_prepare_v47 AS ( + SELECT + DATE_BUCKET(hour, 11, CAST('23:23:56.846362' AS TIME), CAST('12:23:56.846363' AS TIME)) AS HOURS_BUCKET, + DATE_BUCKET(minute, 11, CAST('01:23:56.846362' AS TIME), CAST('01:12:56.846363' AS TIME)) AS MINUTES_BUCKET, + DATE_BUCKET(second, 10, CAST('01:23:50.846362' AS TIME), CAST('01:23:40.846363' AS TIME)) AS SECONDS_BUCKET, + DATE_BUCKET(millisecond, 10,CAST('01:23:50.846362' AS TIME), CAST('01:23:40.846363' AS TIME)) AS MILLISECONDS_BUCKET + ); +GO + +-- Test case when casting of datetime datatype round to fixed bins (e.g. .000, .003, .007) +CREATE VIEW DATE_BUCKET_vu_prepare_v48 AS ( + SELECT + date_bucket(month, 1, cast('2020-09-02 02:12:30.448' as datetime), cast('2010-09-02 02:12:30.451' as datetime)) as db1, + date_bucket(month, 1, cast('2020-09-02 02:12:30.449' as datetime), cast('2010-09-02 02:12:30.451' as datetime)) as db2 + ); +GO + +-- Test when datepart is Abbreviations +CREATE VIEW DATE_BUCKET_vu_prepare_v49 AS ( + SELECT + DATE_BUCKET(dd, 3, cast('2028-02-23' as date), cast('1970-09-23' as date)) as db1, + DATE_BUCKET(d, 5, CAST('2034-09-23 08:34:32.432' as datetime)) as db2, + DATE_BUCKET(wk, 2, cast('2023-09-23' as datetime2), cast('1965-09-25' as datetime2)) as db3, + DATE_BUCKET(ww, 2, cast('2023-09-23' as datetime2), cast('1965-09-25' as datetime2)) as db4, + DATE_BUCKET(mm, 3, cast('2028-02-06' as date), cast('1970-09-23' as date)) as db5, + DATE_BUCKET(m, 5, CAST('2034-09-23 08:34:32.432' as datetime)) as db6, + DATE_BUCKET(qq, 2, cast('2023-09-23' as date), cast('1965-09-25' as date)) as db7, + DATE_BUCKET(q, 2, cast('2023-09-23' as datetime), cast('1965-09-25' as datetime)) as db8, + DATE_BUCKET(yy, 3, cast('2028-02-15' as date), cast('1970-09-23' as date)) as db9, + DATE_BUCKET(yyyy, 5, CAST('2034-09-23 08:34:32.432' as datetime)) as db10, + DATE_BUCKET(hh, 2, cast('2023-09-23 23:43:53.947' as datetime2), cast('1965-09-25 02:43:46.83' as datetime2)) as db11, + DATE_BUCKET(mi, 2, cast('2023-09-23 14:43:56.54 +01:34' as datetimeoffset), cast('1965-09-25 09:43:23.323 +09:10' as datetimeoffset)) as db12, + DATE_BUCKET(n, 2, cast('19:43:56.8362' as time), cast('12:43:56.3223' as time)) as db13, + DATE_BUCKET(ss, 10, cast('2023-09-23 12:32:43.234' as datetime), cast('1965-09-25 09:33:43.847' as datetime)) as db14, + DATE_BUCKET(s, 10, cast('2023-09-23 05:35:12' as smalldatetime), cast('1965-09-25 09:32:32' as smalldatetime)) as db15, + DATE_BUCKET(ms, 2, cast('2023-09-23 11:12:32.64537' as datetime2), cast('1965-09-25 09:32:43.343' as datetime2)) as db16 + ); +GO + +-- Procedures +CREATE PROCEDURE BABEL_3952_vu_prepare_p1 as ( + SELECT + date_bucket(month, 2, cast('2015-10-11' as date)) as db1, + date_bucket(month, 3, cast('2012-04-09' as date)) as db2 + ); +GO + +CREATE PROCEDURE BABEL_3952_vu_prepare_p2 as ( + SELECT + date_bucket(year, 12, cast('2030-01-01 00:00:00 ' as datetime)) as db1, + date_bucket(year, 15, cast('2019-12-23 23:59:59.997' as datetime)) as db2 + ); +GO + +CREATE PROCEDURE BABEL_3952_vu_prepare_p3 as ( + SELECT + date_bucket(hour, 5, cast('2000-01-01 00:00:00' as datetime2)) as dt1, + date_bucket(hour, 5, cast('2020-09-23 12:43:43.43' as datetime2)) as dt2 + ); +GO + +-- Functions +CREATE FUNCTION BABEL_3952_vu_prepare_f1() +RETURNS DATETIME2 AS +BEGIN +RETURN (SELECT date_bucket(week, 7, cast('2012-01-23 12:32:23.324' as datetime2))); +END +GO + +CREATE FUNCTION BABEL_3952_vu_prepare_f2() +RETURNS time AS +BEGIN +RETURN (select date_bucket(second, 19, cast('12:32:53.23' as time), cast('02:12:53.32' as time))); +END +GO + +CREATE FUNCTION BABEL_3952_vu_prepare_f3() +RETURNS date AS +BEGIN +RETURN (select date_bucket(day, 23, cast('2001-11-14' as date), cast('1980-09-10' as date))); +END +GO diff --git a/test/JDBC/expected/BABEL-3952-vu-verify.out b/test/JDBC/expected/BABEL-3952-vu-verify.out new file mode 100644 index 0000000000..947b9bc072 --- /dev/null +++ b/test/JDBC/expected/BABEL-3952-vu-verify.out @@ -0,0 +1,653 @@ +-- Test with null datepart +-- Should Throw Error - 'syntax error at or near "null"' (error from parser side) +select date_bucket(null, 2, cast('2020-01-01' as date)) as db +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "null")~~ + + +select date_bucket(null, null, cast('2020-01-01' as date)) as db2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "null")~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v3 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid bucket width value passed to date_bucket function. Only positive values are allowed.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v4 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type text is invalid for argument 3 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v5 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type NULL is invalid for argument 3 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v6 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type NULL is invalid for argument 2 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v7 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type NULL is invalid for argument 2 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v8 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type NULL is invalid for argument 2 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v9 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type NULL is invalid for argument 3 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v10 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type text is invalid for argument 3 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v11 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type integer is invalid for argument 3 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v11_2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type integer is invalid for argument 3 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v12 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type varchar is invalid for argument 4 of date_bucket function.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v12_origin_IS_NULL +GO +~~START~~ +date +2023-01-01 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v13 +GO +~~START~~ +date#!#date +9999-12-31#!#0001-01-01 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v14 +GO +~~START~~ +datetime +9999-12-31 00:00:00.0 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v15 +GO +~~ERROR (Code: 517)~~ + +~~ERROR (Message: data out of range for datetime)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v16 +GO +~~START~~ +datetime2 +9999-12-31 00:00:00.0000000 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v17 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for datetime2)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v18 +GO +~~START~~ +datetimeoffset +9999-12-31 04:00:00.0000000 +14:00 +~~END~~ + + +-- Should Throw - data out of range for datetimeoffset +select date_bucket(day, 1, cast('0001-01-01 00:00:00 +14:00' as datetimeoffset), cast('9999-12-31 23:59:59.999999 +14:00' as datetimeoffset)) as db1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for datetimeoffset)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v20 +GO +~~START~~ +smalldatetime#!#smalldatetime +2079-06-06 00:00:00.0#!#2079-06-06 00:00:00.0 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v21 +GO +~~START~~ +time#!#time +23:59:00.0000000#!#23:59:59.9999990 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v22 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The datepart year is not supported by date function date_bucket for data type 'time'.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v23 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The datepart hour is not supported by date function date_bucket for data type 'date'.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v24 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The datepart nanosecond is not supported by date function date_bucket for data type datetime2.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_invalid_datepart +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: dayofmonth is not a recognized date_bucket option.)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v25 +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v26 +GO +~~START~~ +datetime2 +2020-04-29 00:00:00.0000000 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v27 +GO +~~START~~ +date#!#date#!#date#!#date#!#date +2000-01-01#!#2000-01-01#!#2000-01-01#!#2000-01-01#!#1999-12-20 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v28 +GO +~~START~~ +date#!#date#!#date#!#date#!#date +1999-09-12#!#1999-09-12#!#1999-11-12#!#2000-01-01#!#1999-12-28 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v29 +GO +~~START~~ +date#!#date#!#date#!#date#!#date +1998-09-21#!#1999-09-21#!#1999-11-21#!#2000-01-01#!#1999-12-28 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v30 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +2000-01-01 00:00:00.0#!#2000-01-01 00:00:00.0#!#2000-01-01 00:00:00.0#!#2000-01-01 00:00:00.0#!#1999-12-20 00:00:00.0#!#2000-01-01 22:00:00.0#!#2000-01-01 23:30:00.0#!#2000-01-01 23:30:04.0#!#2000-01-01 23:30:05.523 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v31 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1998-09-12 23:45:10.433#!#1999-09-12 23:45:10.433#!#1999-11-12 23:45:10.433#!#1999-12-30 23:45:10.433#!#1999-12-20 23:45:10.433#!#2000-01-01 21:45:10.433#!#2000-01-01 23:29:10.433#!#2000-01-01 23:30:04.433#!#2000-01-01 23:30:05.523 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v32 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +1910-01-01 23:30:05.523#!#1910-07-01 23:30:05.523#!#1910-09-01 23:30:05.523#!#1910-09-12 23:30:05.523#!#1910-09-10 23:30:05.523#!#1910-09-12 23:30:05.523#!#1910-09-12 23:44:05.523#!#1910-09-12 23:45:09.523#!#1910-09-12 23:45:10.433 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v33 +GO +~~START~~ +datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2 +2000-01-01 00:00:00.0000000#!#2000-01-01 00:00:00.0000000#!#2000-01-01 00:00:00.0000000#!#2000-01-01 00:00:00.0000000#!#1999-12-20 00:00:00.0000000#!#2000-01-01 22:00:00.0000000#!#2000-01-01 23:30:00.0000000#!#2000-01-01 23:30:04.0000000#!#2000-01-01 23:30:05.5220000 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v34 +GO +~~START~~ +datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2 +1999-08-15 22:35:05.4224560#!#1999-08-15 22:35:05.4224560#!#1999-12-15 22:35:05.4224560#!#2000-01-01 22:35:05.4224560#!#1999-12-26 22:35:05.4224560#!#2000-01-01 22:35:05.4224560#!#2000-01-01 23:29:05.4224560#!#2000-01-01 23:30:05.4224560#!#2000-01-01 23:30:05.5224560 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v35 +GO +~~START~~ +datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2 +1916-01-01 23:30:05.5234560#!#1916-07-01 23:30:05.5234560#!#1916-07-01 23:30:05.5234560#!#1916-08-13 23:30:05.5234560#!#1916-08-05 23:30:05.5234560#!#1916-08-15 21:30:05.5234560#!#1916-08-15 22:34:05.5234560#!#1916-08-15 22:35:03.5234560#!#1916-08-15 22:35:05.4214560 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v36 +GO +~~START~~ +datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2 +2019-08-02 02:12:30.4467000#!#2020-07-02 02:12:30.4467000#!#2020-02-02 02:12:30.4467000#!#2020-06-30 02:12:30.4467000#!#2020-08-02 02:12:30.4467000#!#2020-08-02 02:12:30.4467000#!#2020-08-02 02:12:30.4467000#!#2020-08-02 02:12:30.4467000#!#2020-08-02 02:12:30.4467000#!#2020-08-02 02:12:30.4447000 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v37 +GO +~~START~~ +datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset +2000-01-01 02:00:00.0000000 +02:00#!#2000-01-01 09:20:00.0000000 +09:20#!#1999-11-01 13:10:00.0000000 +13:10#!#2000-01-01 10:23:00.0000000 +10:23#!#1999-12-19 13:28:00.0000000 -10:32#!#2000-01-01 12:08:00.0000000 +12:08#!#2000-01-01 12:24:00.0000000 -08:10#!#2000-01-01 12:25:32.0000000 +00:00#!#2000-01-01 12:25:32.0000000 +11:00 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v38 +GO +~~START~~ +datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset +1998-03-22 13:20:31.0000000 +02:12#!#1999-09-22 13:21:31.0000000 +01:11#!#1999-11-22 14:15:31.0000000 +04:10#!#1999-12-30 22:18:31.0000000 -03:00#!#1999-12-27 10:42:31.0000000 -05:02#!#2000-01-01 10:46:31.0000000 -01:05#!#2000-01-01 12:24:31.0000000 +00:09#!#2000-01-01 12:25:31.0000000 +10:17#!#2000-01-01 12:25:32.0000000 +07:20 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v39 +GO +~~START~~ +datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset +1920-01-01 15:42:32.0000000 +02:12#!#1920-01-01 16:35:32.0000000 +01:10#!#1920-03-01 20:42:32.0000000 +03:15#!#1920-03-21 14:10:32.0000000 +12:02#!#1920-03-13 08:50:32.0000000 -02:24#!#1920-03-22 12:56:32.0000000 +03:29#!#1920-03-22 13:18:32.0000000 -06:45#!#1920-03-22 13:20:30.0000000 +05:10#!#1920-03-22 13:20:31.0000000 +12:32 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v40 +GO +~~START~~ +datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset +2019-08-02 02:12:30.4467000 +00:00#!#2020-07-02 02:12:30.4467000 +00:00#!#2020-02-02 02:12:30.4467000 +00:00#!#2020-06-30 02:12:30.4467000 +00:00#!#2020-08-02 02:12:30.4467000 +00:00#!#2020-08-02 02:12:30.4467000 +00:00#!#2020-08-02 02:12:30.4467000 +00:00#!#2020-08-02 02:12:30.4467000 +00:00#!#2020-08-02 02:12:30.4467000 +00:00#!#2020-08-02 02:12:30.4447000 +00:00 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v41 +GO +~~START~~ +smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime +2000-01-01 00:00:00.0#!#2000-01-01 00:00:00.0#!#2000-01-01 00:00:00.0#!#2000-01-01 00:00:00.0#!#1999-12-20 00:00:00.0#!#2000-01-01 22:00:00.0#!#2000-01-01 23:58:00.0#!#2000-01-01 23:59:00.0#!#2000-01-01 23:59:00.0 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v42 +GO +~~START~~ +smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime +1999-02-11 21:56:00.0#!#1999-08-11 21:56:00.0#!#1999-12-11 21:56:00.0#!#2000-01-01 21:56:00.0#!#1999-12-30 21:56:00.0#!#2000-01-01 23:56:00.0#!#2000-01-01 23:58:00.0#!#2000-01-01 23:59:00.0#!#2000-01-01 23:59:00.0 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v43 +GO +~~START~~ +smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime +1910-01-01 23:59:00.0#!#1911-01-01 23:59:00.0#!#1911-01-01 23:59:00.0#!#1911-02-09 23:59:00.0#!#1911-01-28 23:59:00.0#!#1911-02-11 19:59:00.0#!#1911-02-11 21:55:00.0#!#1911-02-11 21:56:00.0#!#1911-02-11 21:56:00.0 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v44 +GO +~~START~~ +time#!#time#!#time#!#time +22:00:00.0000000#!#23:58:00.0000000#!#23:58:58.0000000#!#23:58:59.0000000 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v45 +GO +~~START~~ +time#!#time#!#time#!#time +22:23:56.8463630#!#23:57:56.8463630#!#23:58:58.8463630#!#23:58:59.5463630 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v46 +GO +~~START~~ +time#!#time#!#time#!#time +11:58:59.5464460#!#12:22:59.5464460#!#12:23:55.5464460#!#12:23:56.8464460 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v47 +GO +~~START~~ +time#!#time#!#time#!#time +23:23:56.8463630#!#01:23:56.8463630#!#01:23:50.8463630#!#01:23:50.8463630 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v48 +GO +~~START~~ +datetime#!#datetime +2020-08-02 02:12:30.45#!#2020-09-02 02:12:30.45 +~~END~~ + + +SELECT * FROM DATE_BUCKET_vu_prepare_v49 +GO +~~START~~ +date#!#datetime#!#datetime2#!#datetime2#!#date#!#datetime#!#date#!#datetime#!#date#!#datetime#!#datetime2#!#datetimeoffset#!#time#!#datetime#!#smalldatetime#!#datetime2 +2028-02-21#!#2034-09-20 00:00:00.0#!#2023-09-23 00:00:00.0000000#!#2023-09-23 00:00:00.0000000#!#2027-12-23#!#2034-08-01 00:00:00.0#!#2023-03-25#!#2023-03-25 00:00:00.0#!#2027-09-23#!#2030-01-01 00:00:00.0#!#2023-09-23 22:43:46.8300000#!#2023-09-23 14:43:23.3230000 +01:34#!#19:43:56.3223000#!#2023-09-23 12:32:33.847#!#2023-09-23 05:35:00.0#!#2023-09-23 11:12:32.6450000 +~~END~~ + + +SELECT DATE_BUCKET(m, 5, CAST('2034-09-23 08:34:32.432' as datetime)) as db6 +GO +~~START~~ +datetime +2034-08-01 00:00:00.0 +~~END~~ + + +SELECT DATE_BUCKET(month, 2, CAST('2000-01-01 23:58:59' AS SMALLDATETIME), CAST('1909-02-11 21:55:56' AS SMALLDATETIME)) AS MONTHS_BUCKET +GO +~~START~~ +smalldatetime +1999-12-11 21:56:00.0 +~~END~~ + + +SELECT DATE_BUCKET(day, 2, CAST('1916-08-15 22:35:05.422456' AS DATETIME2), CAST('2000-01-01 23:30:05.523456' AS DATETIME2)) AS DAYS_BUCKET +GO +~~START~~ +datetime2 +1916-08-13 23:30:05.5234560 +~~END~~ + + +SELECT DATE_BUCKET(month, 2, CAST('2000-01-01' AS DATE), CAST('1905-09-12' AS DATE)) AS MONTHS_BUCKET +GO +~~START~~ +date +1999-11-12 +~~END~~ + + +SELECT date_bucket(second, 1, cast('2020-08-02 02:12:30.4463 +00:00' as datetimeoffset), cast('2019-08-02 02:12:30.4467 +00:00' as datetimeoffset)) AS second_BUCKET +GO +~~START~~ +datetimeoffset +2020-08-02 02:12:30.4467000 +00:00 +~~END~~ + + +SELECT DATE_BUCKET(second, 2, CAST('12:23:56.846363' AS TIME), CAST('23:58:59.546446' AS TIME)) AS SECONDS_BUCKET +GO +~~START~~ +time +12:23:55.5464460 +~~END~~ + + +EXEC BABEL_3952_vu_prepare_p1 +GO +~~START~~ +date#!#date +2015-09-01#!#2012-04-01 +~~END~~ + + +EXEC BABEL_3952_vu_prepare_p2 +GO +~~START~~ +datetime#!#datetime +2020-01-01 00:00:00.0#!#2005-01-01 00:00:00.0 +~~END~~ + + +EXEC BABEL_3952_vu_prepare_p3 +GO +~~START~~ +datetime2#!#datetime2 +1999-12-31 23:00:00.0000000#!#2020-09-23 10:00:00.0000000 +~~END~~ + + +SELECT BABEL_3952_vu_prepare_f1() +GO +~~START~~ +datetime2 +2012-01-09 00:00:00.0000000 +~~END~~ + + +SELECT BABEL_3952_vu_prepare_f2() +GO +~~START~~ +time +12:32:36.3200000 +~~END~~ + + +SELECT BABEL_3952_vu_prepare_f3() +GO +~~START~~ +date +2001-11-07 +~~END~~ + + +DECLARE @test_date date; +SET @test_date = '1998-09-12'; +SELECT date_bucket(day,109, @test_date); +GO +~~START~~ +date +1998-06-26 +~~END~~ + + +DECLARE @test_date datetime; +SET @test_date = '2010-09-12 12:23:12.564'; +SELECT date_bucket(hour,200, @test_date); +GO +~~START~~ +datetime +2010-09-06 00:00:00.0 +~~END~~ + + +DECLARE @test_date datetime2; +SET @test_date = '2010-09-12 12:23:12.56443'; +SELECT date_bucket(week, 19, @test_date); +GO +~~START~~ +datetime2 +2010-05-03 00:00:00.0000000 +~~END~~ + + +DECLARE @test_date smalldatetime; +SET @test_date = '2010-09-12 12:23:12'; +SELECT date_bucket(week, 3, @test_date); +GO +~~START~~ +smalldatetime +2010-09-06 00:00:00.0 +~~END~~ + + +DECLARE @test_date datetimeoffset; +SET @test_date = '2010-09-12 12:23:12.56443 +10:12'; +SELECT date_bucket(week,5, @test_date); +GO +~~START~~ +datetimeoffset +2010-09-06 10:12:00.0000000 +10:12 +~~END~~ + + +DECLARE @test_date time; +SET @test_date = '12:23:12.56443'; +SELECT date_bucket(hour,12, @test_date); +GO +~~START~~ +time +12:00:00.0000000 +~~END~~ + + +DROP TABLE IF EXISTS dbucket +GO +Create table dbucket(a datetime) +insert into dbucket (a) values(date_bucket(day, 21, CAST('2020-01-09 12:32:23.23' as datetime))) +Select * from dbucket +Select date_bucket(week,12, a) from dbucket +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetime +2019-12-30 00:00:00.0 +~~END~~ + +~~START~~ +datetime +2019-10-28 00:00:00.0 +~~END~~ + + +DROP TABLE IF EXISTS dbucket +GO +Create table dbucket(a date) +insert into dbucket (a) values(date_bucket(month, 24, CAST('2020-01-09' as date))) +Select * from dbucket +Select date_bucket(week,23, a) from dbucket +GO +~~ROW COUNT: 1~~ + +~~START~~ +date +2020-01-01 +~~END~~ + +~~START~~ +date +2019-11-25 +~~END~~ + + +DROP TABLE IF EXISTS dbucket +GO +Create table dbucket(a datetimeoffset) +insert into dbucket (a) values(date_bucket(day, 123, CAST('2020-01-09 12:32:23.23 -10:23' as datetimeoffset))) +Select * from dbucket +Select date_bucket(month,3, a) from dbucket +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetimeoffset +2019-11-20 13:37:00.0000000 -10:23 +~~END~~ + +~~START~~ +datetimeoffset +2019-09-30 13:37:00.0000000 -10:23 +~~END~~ + + +DROP TABLE IF EXISTS dbucket +GO +Create table dbucket(a smalldatetime) +insert into dbucket (a) values(date_bucket(week, 9, CAST('2020-01-09 12:32:23' as smalldatetime))) +Select * from dbucket +Select date_bucket(hour,4, a) from dbucket +GO +~~ROW COUNT: 1~~ + +~~START~~ +smalldatetime +2019-11-18 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2019-11-18 00:00:00.0 +~~END~~ + + +DROP TABLE IF EXISTS dbucket +GO +Create table dbucket(a time) +insert into dbucket (a) values(date_bucket(minute,12, CAST('12:32:23.23' as time))) +Select * from dbucket +Select date_bucket(second,10, a) from dbucket +GO +~~ROW COUNT: 1~~ + +~~START~~ +time +12:24:00.0000000 +~~END~~ + +~~START~~ +time +12:24:00.0000000 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-3953-datetrunc-vu-cleanup.out b/test/JDBC/expected/BABEL-3953-datetrunc-vu-cleanup.out new file mode 100644 index 0000000000..53d3e86cb9 --- /dev/null +++ b/test/JDBC/expected/BABEL-3953-datetrunc-vu-cleanup.out @@ -0,0 +1,59 @@ +DROP VIEW DATETRUNC_vu_prepare_v1 +GO + +DROP VIEW DATETRUNC_vu_prepare_v2 +GO + +DROP VIEW DATETRUNC_vu_prepare_v3 +GO + +DROP VIEW DATETRUNC_vu_prepare_v4 +GO + +DROP VIEW DATETRUNC_vu_prepare_v5 +GO + +DROP VIEW DATETRUNC_vu_prepare_v6 +GO + +DROP VIEW DATETRUNC_vu_prepare_v7 +GO + +DROP VIEW DATETRUNC_vu_prepare_v8 +GO + +DROP VIEW DATETRUNC_vu_prepare_v9 +GO + +DROP VIEW DATETRUNC_vu_prepare_v10 +GO + +DROP VIEW DATETRUNC_vu_prepare_v11 +GO + +DROP PROCEDURE BABEL_3953_vu_prepare_p1 +GO + +DROP PROCEDURE BABEL_3953_vu_prepare_p2 +GO + +DROP PROCEDURE BABEL_3953_vu_prepare_p3 +GO + +DROP PROCEDURE BABEL_3953_vu_prepare_p4 +GO + +DROP PROCEDURE BABEL_3953_vu_prepare_p5 +GO + +DROP PROCEDURE BABEL_3953_vu_prepare_p6 +GO + +DROP FUNCTION BABEL_3953_vu_prepare_f1 +GO + +DROP FUNCTION BABEL_3953_vu_prepare_f2 +GO + +DROP FUNCTION BABEL_3953_vu_prepare_f3 +GO diff --git a/test/JDBC/expected/BABEL-3953-datetrunc-vu-prepare.out b/test/JDBC/expected/BABEL-3953-datetrunc-vu-prepare.out new file mode 100644 index 0000000000..51dc0df6e2 --- /dev/null +++ b/test/JDBC/expected/BABEL-3953-datetrunc-vu-prepare.out @@ -0,0 +1,233 @@ +-- Test with date datatype +CREATE VIEW DATETRUNC_vu_prepare_v1 AS ( + select + datetrunc(year, cast('2020-04-15' as date)) as dt1, + datetrunc(yy, cast('2020-04-15' as date)) as dt2, + datetrunc(yyyy, cast('2020-04-15' as date)) as dt3, + datetrunc(quarter, cast('2020-04-15' as date)) as dt4, + datetrunc(qq, cast('2020-04-15' as date)) as dt5, + datetrunc(q, cast('2020-04-15' as date)) as dt6, + datetrunc(month, cast('2020-04-15' as date)) as dt7, + datetrunc(mm, cast('2020-04-15' as date)) as dt8, + datetrunc(m, cast('2020-04-15' as date)) as dt9, + datetrunc(dayofyear, cast('2020-04-15' as date)) as dt10, + datetrunc(dy, cast('2020-04-15' as date)) as dt11, + datetrunc(y, cast('2020-04-15' as date)) as dt12, + datetrunc(day, cast('2020-04-15' as date)) as dt13, + datetrunc(dd, cast('2020-04-15' as date)) as dt14, + datetrunc(d, cast('2020-04-15' as date)) as dt15, + datetrunc(week, cast('2020-04-15' as date)) as dt16, + datetrunc(wk, cast('2020-04-15' as date)) as dt17, + datetrunc(ww, cast('2020-04-15' as date)) as dt18, + datetrunc(iso_week, cast('2020-04-15' as date)) as dt19, + datetrunc(isowk, cast('2020-04-15' as date)) as dt20, + datetrunc(isoww, cast('2020-04-15' as date)) as dt21 + ); +GO + +-- Test with time datatype +CREATE VIEW DATETRUNC_vu_prepare_v2 AS ( + select + datetrunc(hour, cast('12:32:45.5647311' as time)) as dt1, + datetrunc(hh, cast('12:32:45.5647311' as time)) as dt2, + datetrunc(minute, cast('12:32:45.5647311' as time)) as dt3, + datetrunc(mi, cast('12:32:45.5647311' as time)) as dt4, + datetrunc(n, cast('12:32:45.5647311' as time)) as dt5, + datetrunc(second, cast('12:32:45.5647311' as time)) as dt6, + datetrunc(ss, cast('12:32:45.5647311' as time)) as dt7, + datetrunc(s, cast('12:32:45.5647311' as time)) as dt8, + datetrunc(millisecond, cast('12:32:45.5647311' as time)) as dt9, + datetrunc(ms, cast('12:32:45.5647311' as time)) as dt10, + datetrunc(microsecond, cast('12:32:45.5647311' as time)) as dt11, + datetrunc(mcs, cast('12:32:45.5647311' as time)) as dt12 + ); +GO + + +-- Test with datetime datatype +CREATE VIEW DATETRUNC_vu_prepare_v3 AS ( + select + datetrunc(year, cast('2004-06-17 09:32:42.566' as datetime)) as dt1, + datetrunc(quarter, cast('2004-06-17 09:32:42.566' as datetime)) as dt2, + datetrunc(month, cast('2004-06-17 09:32:42.566' as datetime)) as dt3, + datetrunc(dayofyear, cast('2004-06-17 09:32:42.566' as datetime)) as dt4, + datetrunc(day, cast('2004-06-17 09:32:42.566' as datetime)) as dt5, + datetrunc(week, cast('2004-06-17 09:32:42.566' as datetime)) as dt6, + datetrunc(hour, cast('2004-06-17 09:32:42.566' as datetime)) as dt7, + datetrunc(minute, cast('2004-06-17 09:32:42.566' as datetime)) as dt8, + datetrunc(second, cast('2004-06-17 09:32:42.566' as datetime)) as dt9, + datetrunc(millisecond, cast('2004-06-17 09:32:42.566' as datetime)) as dt10 + ); +GO +-- Should throw exception - 'datepart 'microsecond' is not supported by date function datetrunc for data type ''datetime''. +CREATE VIEW DATETRUNC_vu_prepare_v4 AS ( + select + datetrunc(microsecond, cast('2004-06-17 09:32:42.566' as datetime)) as dt1 +); +GO + +-- Test with smalldatetime datatype +CREATE VIEW DATETRUNC_vu_prepare_v5 AS ( + select + datetrunc(year, cast('2004-08-14 22:34:20' as smalldatetime)) as dt1, + datetrunc(quarter, cast('2004-08-14 22:34:20' as smalldatetime)) as dt2, + datetrunc(month, cast('2004-08-14 22:34:20' as smalldatetime)) as dt3, + datetrunc(dayofyear, cast('2004-08-14 22:34:20' as smalldatetime)) as dt4, + datetrunc(day, cast('2004-08-14 22:34:20' as smalldatetime)) as dt5, + datetrunc(week, cast('2004-08-14 22:34:20' as smalldatetime)) as dt6, + datetrunc(hour, cast('2004-08-14 22:34:20' as smalldatetime)) as dt7, + datetrunc(minute, cast('2004-08-14 22:34:20' as smalldatetime)) as dt8, + datetrunc(second, cast('2004-08-14 22:34:20' as smalldatetime)) as dt9 + ); +GO + +-- Should throw exception - 'datepart 'microsecond' is not supported by date function datetrunc for data type ''smalldatetime''. +CREATE VIEW DATETRUNC_vu_prepare_v6 AS ( + select + datetrunc(microsecond, cast('2004-08-14 22:34:20' as smalldatetime)) as dt1, + datetrunc(millisecond, cast('2004-08-14 22:34:20' as smalldatetime)) as dt2 +); +GO + +-- Test with datetime2 datatype +CREATE VIEW DATETRUNC_vu_prepare_v7 AS ( + select + datetrunc(year, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt1, + datetrunc(quarter, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt2, + datetrunc(month, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt3, + datetrunc(dayofyear, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt4, + datetrunc(day, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt5, + datetrunc(week, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt6, + datetrunc(hour, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt7, + datetrunc(minute, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt8, + datetrunc(second, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt9, + datetrunc(millisecond, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt10, + datetrunc(microsecond, cast('2015-11-30 09:34:56.6574893' as datetime2)) as dt11 + ); +GO + +-- Test with datetimeoffset datatype +CREATE VIEW DATETRUNC_vu_prepare_v8 AS ( + select + datetrunc(year, cast('2015-11-30 09:34:56.6574893 +12:42' as datetimeoffset)) as dt1, + datetrunc(quarter, cast('2015-11-30 09:34:56.6574893 +10:42' as datetimeoffset)) as dt2, + datetrunc(month, cast('2015-11-30 09:34:56.6574893 +02:42' as datetimeoffset)) as dt3, + datetrunc(dayofyear, cast('2015-11-30 09:34:56.6574893 +05:42' as datetimeoffset)) as dt4, + datetrunc(day, cast('2015-11-30 09:34:56.6574893 +12:42' as datetimeoffset)) as dt5, + datetrunc(week, cast('2015-11-30 09:34:56.6574893 +13:42' as datetimeoffset)) as dt6, + datetrunc(hour, cast('2015-11-30 09:34:56.6574893 +12:42' as datetimeoffset)) as dt7, + datetrunc(minute, cast('2015-11-30 09:34:56.6574893 -12:43' as datetimeoffset)) as dt8, + datetrunc(second, cast('2015-11-30 09:34:56.6574893 +12:22' as datetimeoffset)) as dt9, + datetrunc(millisecond, cast('2015-11-30 09:34:56.6574893 -10:42' as datetimeoffset)) as dt10, + datetrunc(microsecond, cast('2015-11-30 09:34:56.6574893 +12:42' as datetimeoffset)) as dt11 + ); +GO + +-- Test with expression input that can be converted to datetime2 datatype. +CREATE VIEW DATETRUNC_vu_prepare_v9 AS ( + select + datetrunc(year, '2021-Jan-01') as dt1, + datetrunc(year, '2021/Jan/01') as dt2, + datetrunc(year, '2021-1-1') as dt3, + datetrunc(year, '20210101') as dt4, + datetrunc(hour, cast('2020-01-01' as varchar)) as dt5, + datetrunc(minute, cast('1980-09-08' as char)) as dt6, + datetrunc(day, '12:32:42') as dt7, + datetrunc(day, '12:32:42.46378') as dt8, + datetrunc(week, '1990-09-09 12:32:09.546') as dt9, + datetrunc(week, '1990-09-09 12:32:09') as dt10, + datetrunc(week, '1990-09-09 12:32:09.546788') as dt11 + ); +GO + +-- Test when time, datetime2, datetimeoffset casted to a specified fractional scale +-- babelfish will always give answer that will include fractional seconds till 7 digits. +CREATE VIEW DATETRUNC_vu_prepare_v10 AS ( + select + datetrunc(hour, cast('12:32:43.4635' as time(3))) dt1, + datetrunc(month, cast('2020-12-23 20:20:20.2222' as datetime2(2))) as dt2, + datetrunc(week, cast('1989-09-23 05:36:43.2930 +12:37' as datetimeoffset(5))) as dt3, + datetrunc(minute, cast('2027-12-13 10:13:20.12236' as datetime2(4))) as dt4, + datetrunc(year, cast('2027-12-13 10:13:20.537478' as datetimeoffset(6))) as dt5 + ); +GO + +-- Test when time, datetime2, datetimeoffset casted to a specified fractional scale which is less then the specified datepart milliseocond, microsecond. +-- Babelfish always give answer to these with fractional seconds till 7 digits, babelfish do not throw an error similar to sql server in this case. +CREATE VIEW DATETRUNC_vu_prepare_v11 AS ( + select + datetrunc(millisecond, cast('2002-01-01 12:33:43.435354' as datetime2(2))) as dt1, + datetrunc(millisecond, cast('2020-01-01 12:33:32.4324' as datetimeoffset(1))) as dt2, + datetrunc(millisecond, cast('12:23:43.464774' as time(0))) as dt3, + datetrunc(microsecond, cast('2002-01-01 12:33:43.435354' as datetime2(5))) as dt4, + datetrunc(microsecond, cast('2020-01-01 12:33:32.437724' as datetimeoffset(4))) as dt5 + ); +GO + + +-- Procedures +-- Test with upper/lower limit of date/time. +CREATE PROCEDURE BABEL_3953_vu_prepare_p1 as ( + SELECT + datetrunc(month, cast('0001-01-01' as date)) as dt1, + datetrunc(month, cast('9999-12-31' as date)) as dt2 + ); +GO + +CREATE PROCEDURE BABEL_3953_vu_prepare_p2 as ( + SELECT + datetrunc(month, cast('1753-01-01 00:00:00 ' as datetime)) as dt1, + datetrunc(month, cast('9999-12-31 23:59:59.997' as datetime)) as dt2 + ); +GO + +CREATE PROCEDURE BABEL_3953_vu_prepare_p3 as ( + SELECT + datetrunc(month, cast('0001-01-01 00:00:00' as datetime2)) as dt1, + datetrunc(month, cast('9999-12-31 23:59:59.9999999' as datetime2)) as dt2 + ); +GO + +CREATE PROCEDURE BABEL_3953_vu_prepare_p4 as ( + SELECT + datetrunc(month, cast('0001-01-01 00:00:00 -14:00' as datetimeoffset)) as dt1, + datetrunc(month, cast('9999-12-31 23:59:59.9999 +14:00' as datetimeoffset)) as dt2 + ); +GO + +CREATE PROCEDURE BABEL_3953_vu_prepare_p5 as ( + SELECT + datetrunc(month, cast('1900-01-01 00:00:00' as smalldatetime)) as dt1, + datetrunc(day, cast('2007-06-05 23:59:59' as smalldatetime)) as dt2 + ); +GO + +CREATE PROCEDURE BABEL_3953_vu_prepare_p6 as ( + SELECT + datetrunc(hour, cast('00:00:00.0000000' as time)) as dt1, + datetrunc(second, cast('23:59:59.999999' as time)) as dt2 + ); +GO + + +-- functions +CREATE FUNCTION BABEL_3953_vu_prepare_f1() +RETURNS DATETIME2 AS +BEGIN +RETURN (SELECT datetrunc(iso_week, cast('2012-01-23 12:32:23.324' as datetime2))); +END +GO + +CREATE FUNCTION BABEL_3953_vu_prepare_f2() +RETURNS time AS +BEGIN +RETURN (select datetrunc(second, cast('12:32:53.23' as time))); +END +GO + +CREATE FUNCTION BABEL_3953_vu_prepare_f3() +RETURNS date AS +BEGIN +RETURN (select datetrunc(week, cast('2001-11-14' as date))); +END +GO diff --git a/test/JDBC/expected/BABEL-3953-datetrunc-vu-verify.out b/test/JDBC/expected/BABEL-3953-datetrunc-vu-verify.out new file mode 100644 index 0000000000..4c15424174 --- /dev/null +++ b/test/JDBC/expected/BABEL-3953-datetrunc-vu-verify.out @@ -0,0 +1,561 @@ +SELECT * FROM DATETRUNC_vu_prepare_v1 +GO +~~START~~ +date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date#!#date +2020-01-01#!#2020-01-01#!#2020-01-01#!#2020-04-01#!#2020-04-01#!#2020-04-01#!#2020-04-01#!#2020-04-01#!#2020-04-01#!#2020-04-15#!#2020-04-15#!#2020-04-15#!#2020-04-15#!#2020-04-15#!#2020-04-15#!#2020-04-12#!#2020-04-12#!#2020-04-12#!#2020-04-13#!#2020-04-13#!#2020-04-13 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v2 +GO +~~START~~ +time#!#time#!#time#!#time#!#time#!#time#!#time#!#time#!#time#!#time#!#time#!#time +12:00:00.0000000#!#12:00:00.0000000#!#12:32:00.0000000#!#12:32:00.0000000#!#12:32:00.0000000#!#12:32:45.0000000#!#12:32:45.0000000#!#12:32:45.0000000#!#12:32:45.5640000#!#12:32:45.5640000#!#12:32:45.5647310#!#12:32:45.5647310 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v3 +GO +~~START~~ +datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime#!#datetime +2004-01-01 00:00:00.0#!#2004-04-01 00:00:00.0#!#2004-06-01 00:00:00.0#!#2004-06-17 00:00:00.0#!#2004-06-17 00:00:00.0#!#2004-06-13 00:00:00.0#!#2004-06-17 09:00:00.0#!#2004-06-17 09:32:00.0#!#2004-06-17 09:32:42.0#!#2004-06-17 09:32:42.567 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v4 +GO +~~START~~ +datetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The datepart 'microsecond' is not supported by date function datetrunc for data type 'datetime'.)~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v5 +GO +~~START~~ +smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime#!#smalldatetime +2004-01-01 00:00:00.0#!#2004-07-01 00:00:00.0#!#2004-08-01 00:00:00.0#!#2004-08-14 00:00:00.0#!#2004-08-14 00:00:00.0#!#2004-08-08 00:00:00.0#!#2004-08-14 22:00:00.0#!#2004-08-14 22:34:00.0#!#2004-08-14 22:34:00.0 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v6 +GO +~~START~~ +smalldatetime#!#smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The datepart 'microsecond' is not supported by date function datetrunc for data type 'smalldatetime'.)~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v7 +GO +~~START~~ +datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2 +2015-01-01 00:00:00.0000000#!#2015-10-01 00:00:00.0000000#!#2015-11-01 00:00:00.0000000#!#2015-11-30 00:00:00.0000000#!#2015-11-30 00:00:00.0000000#!#2015-11-29 00:00:00.0000000#!#2015-11-30 09:00:00.0000000#!#2015-11-30 09:34:00.0000000#!#2015-11-30 09:34:56.0000000#!#2015-11-30 09:34:56.6570000#!#2015-11-30 09:34:56.6574890 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v8 +GO +~~START~~ +datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset#!#datetimeoffset +2015-01-01 00:00:00.0000000 +12:42#!#2015-10-01 00:00:00.0000000 +10:42#!#2015-11-01 00:00:00.0000000 +02:42#!#2015-11-30 00:00:00.0000000 +05:42#!#2015-11-30 00:00:00.0000000 +12:42#!#2015-11-29 00:00:00.0000000 +13:42#!#2015-11-30 09:00:00.0000000 +12:42#!#2015-11-30 09:34:00.0000000 -12:43#!#2015-11-30 09:34:56.0000000 +12:22#!#2015-11-30 09:34:56.6570000 -10:42#!#2015-11-30 09:34:56.6574890 +12:42 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v9 +GO +~~START~~ +datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2#!#datetime2 +2021-01-01 00:00:00.0000000#!#2021-01-01 00:00:00.0000000#!#2021-01-01 00:00:00.0000000#!#2021-01-01 00:00:00.0000000#!#2020-01-01 00:00:00.0000000#!#1980-09-08 00:00:00.0000000#!#1900-01-01 00:00:00.0000000#!#1900-01-01 00:00:00.0000000#!#1990-09-09 00:00:00.0000000#!#1990-09-09 00:00:00.0000000#!#1990-09-09 00:00:00.0000000 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v10 +GO +~~START~~ +time#!#datetime2#!#datetimeoffset#!#datetime2#!#datetimeoffset +12:00:00.0000000#!#2020-12-01 00:00:00.0000000#!#1989-09-17 00:00:00.0000000 +12:37#!#2027-12-13 10:13:00.0000000#!#2027-01-01 00:00:00.0000000 +00:00 +~~END~~ + + +SELECT * FROM DATETRUNC_vu_prepare_v11 +GO +~~START~~ +datetime2#!#datetimeoffset#!#time#!#datetime2#!#datetimeoffset +2002-01-01 12:33:43.4400000#!#2020-01-01 12:33:32.4000000 +00:00#!#12:23:43.0000000#!#2002-01-01 12:33:43.4353500#!#2020-01-01 12:33:32.4377000 +00:00 +~~END~~ + + +EXEC BABEL_3953_vu_prepare_p1 +GO +~~START~~ +date#!#date +0001-01-01#!#9999-12-01 +~~END~~ + + +EXEC BABEL_3953_vu_prepare_p2 +GO +~~START~~ +datetime#!#datetime +1753-01-01 00:00:00.0#!#9999-12-01 00:00:00.0 +~~END~~ + + +EXEC BABEL_3953_vu_prepare_p3 +GO +~~START~~ +datetime2#!#datetime2 +0001-01-01 00:00:00.0000000#!#9999-12-01 00:00:00.0000000 +~~END~~ + + +EXEC BABEL_3953_vu_prepare_p4 +GO +~~START~~ +datetimeoffset#!#datetimeoffset +0001-01-01 00:00:00.0000000 -14:00#!#9999-12-01 00:00:00.0000000 +14:00 +~~END~~ + + +EXEC BABEL_3953_vu_prepare_p5 +GO +~~START~~ +smalldatetime#!#smalldatetime +1900-01-01 00:00:00.0#!#2007-06-06 00:00:00.0 +~~END~~ + + +EXEC BABEL_3953_vu_prepare_p6 +GO +~~START~~ +time#!#time +00:00:00.0000000#!#23:59:59.0000000 +~~END~~ + + +SELECT BABEL_3953_vu_prepare_f1() +GO +~~START~~ +datetime2 +2012-01-23 00:00:00.0000000 +~~END~~ + + +SELECT BABEL_3953_vu_prepare_f2() +GO +~~START~~ +time +12:32:53.0000000 +~~END~~ + + +SELECT BABEL_3953_vu_prepare_f3() +GO +~~START~~ +date +2001-11-11 +~~END~~ + + +select datetrunc(null, CAST('2020-01-01' as date)) as dt1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "null")~~ + +select datetrunc(null, null) as dt1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "null")~~ + +select datetrunc(null, 'NULL') as dt1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "null")~~ + +select datetrunc('NULL', null) as dt1 +GO +~~START~~ +datetime2 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NULL' is not a recognized datetrunc option.)~~ + +select datetrunc('NULL', 'NULL') as dt1 +GO +~~START~~ +datetime2 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'NULL' is not a recognized datetrunc option.)~~ + +select datetrunc('year',CAST('2020-01-01' as date)) +go +~~START~~ +date +2020-01-01 +~~END~~ + +select datetrunc(year, null) as dt3 +GO +~~START~~ +datetime2 + +~~END~~ + +select datetrunc(years, null) as dt4 +GO +~~START~~ +datetime2 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'years' is not a recognized datetrunc option.)~~ + +select datetrunc(nanosecond ,null) as dt5 +GO +~~START~~ +datetime2 + +~~END~~ + +SELECT datetrunc(nanosecond, 2020) +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type 'integer' is invalid for argument 2 of datetrunc function.)~~ + +select datetrunc(invalid_datepart, 2020) +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'invalid_datepart' is not a recognized datetrunc option.)~~ + +select datetrunc(hour, 2020.0) +GO +~~START~~ +numeric +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Argument data type 'numeric' is invalid for argument 2 of datetrunc function.)~~ + + +-- postgres support 6 digits of fractional time-scale so the bbf output will differ +-- in the last fractional second digit from t-sql. bbf- 2021-12-08 11:30:15.1234570 +-- tsql- 2021-12-08 11:30:15.1234560 +DECLARE @d datetime2 = '2021-12-08 11:30:15.1234567'; +SELECT 'Microsecond', DATETRUNC(microsecond, @d); +Go +~~START~~ +varchar#!#datetime2 +Microsecond#!#2021-12-08 11:30:15.1234570 +~~END~~ + + +DECLARE @test_date date; +SET @test_date = '1998-09-12'; +SELECT datetrunc(week, @test_date); +GO +~~START~~ +date +1998-09-06 +~~END~~ + + +DECLARE @test_date datetime; +SET @test_date = '2010-09-12 12:23:12.564'; +SELECT datetrunc(week, @test_date); +GO +~~START~~ +datetime +2010-09-12 00:00:00.0 +~~END~~ + + +DECLARE @test_date datetime2; +SET @test_date = '2010-09-12 12:23:12.56443'; +SELECT datetrunc(week, @test_date); +GO +~~START~~ +datetime2 +2010-09-12 00:00:00.0000000 +~~END~~ + + +DECLARE @test_date smalldatetime; +SET @test_date = '2010-09-12 12:23:12'; +SELECT datetrunc(week, @test_date); +GO +~~START~~ +smalldatetime +2010-09-12 00:00:00.0 +~~END~~ + + +DECLARE @test_date datetimeoffset; +SET @test_date = '2010-09-12 12:23:12.56443 +10:12'; +SELECT datetrunc(week, @test_date); +GO +~~START~~ +datetimeoffset +2010-09-12 00:00:00.0000000 +10:12 +~~END~~ + + +DECLARE @test_date time; +SET @test_date = '12:23:12.56443'; +SELECT datetrunc(hour, @test_date); +GO +~~START~~ +time +12:00:00.0000000 +~~END~~ + + +DROP TABLE IF EXISTS dtrunc +GO +Create table dtrunc(a datetime) +insert into dtrunc (a) values(datetrunc(day, CAST('2020-01-09 12:32:23.23' as datetime))) +Select * from dtrunc +Select datetrunc(week, a) from dtrunc +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetime +2020-01-09 00:00:00.0 +~~END~~ + +~~START~~ +datetime +2020-01-05 00:00:00.0 +~~END~~ + + +DROP TABLE IF EXISTS dtrunc +GO +Create table dtrunc(a date) +insert into dtrunc (a) values(datetrunc(day, CAST('2020-01-09' as date))) +Select * from dtrunc +Select datetrunc(week, a) from dtrunc +GO +~~ROW COUNT: 1~~ + +~~START~~ +date +2020-01-09 +~~END~~ + +~~START~~ +date +2020-01-05 +~~END~~ + + +DROP TABLE IF EXISTS dtrunc +GO +Create table dtrunc(a datetime2) +insert into dtrunc (a) values(datetrunc(day, '2020-01-09 12:32:23.23')) +Select * from dtrunc +Select datetrunc(day, a) from dtrunc +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetime2 +2020-01-09 00:00:00.0000000 +~~END~~ + +~~START~~ +datetime2 +2020-01-09 00:00:00.0000000 +~~END~~ + + +DROP TABLE IF EXISTS dtrunc +GO +Create table dtrunc(a datetimeoffset) +insert into dtrunc (a) values(datetrunc(day, CAST('2020-01-09 12:32:23.23 -10:23' as datetimeoffset))) +Select * from dtrunc +Select datetrunc(month, a) from dtrunc +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetimeoffset +2020-01-09 00:00:00.0000000 -10:23 +~~END~~ + +~~START~~ +datetimeoffset +2020-01-01 00:00:00.0000000 -10:23 +~~END~~ + + +DROP TABLE IF EXISTS dtrunc +GO +Create table dtrunc(a smalldatetime) +insert into dtrunc (a) values(datetrunc(day, CAST('2020-01-09 12:32:23' as smalldatetime))) +Select * from dtrunc +Select datetrunc(hour, a) from dtrunc +GO +~~ROW COUNT: 1~~ + +~~START~~ +smalldatetime +2020-01-09 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2020-01-09 00:00:00.0 +~~END~~ + + +DROP TABLE IF EXISTS dtrunc +GO +Create table dtrunc(a time) +insert into dtrunc (a) values(datetrunc(minute, CAST('12:32:23.23' as time))) +Select * from dtrunc +Select datetrunc(second, a) from dtrunc +GO +~~ROW COUNT: 1~~ + +~~START~~ +time +12:32:00.0000000 +~~END~~ + +~~START~~ +time +12:32:00.0000000 +~~END~~ + + +SET DATEFIRST 1 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-09-13 21:32:32.23' as datetime2)) +SELECT DATETRUNC(WEEK, CAST('2020-09-13 21:32:32.23' as datetime2)) +GO +~~START~~ +datetime2 +2020-09-07 00:00:00.0000000 +~~END~~ + +~~START~~ +datetime2 +2020-09-07 00:00:00.0000000 +~~END~~ + + +SET DATEFIRST 1 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-08-12 21:32:32.23' as datetime2)) +SELECT DATETRUNC(WEEK, CAST('2020-08-12 21:32:32.23' as datetime2)) +GO +~~START~~ +datetime2 +2020-08-10 00:00:00.0000000 +~~END~~ + +~~START~~ +datetime2 +2020-08-10 00:00:00.0000000 +~~END~~ + + +SET DATEFIRST 2 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-01-12 21:32:32.23' as datetime)) +SELECT DATETRUNC(WEEK, CAST('2020-01-12 21:32:32.23' as datetime)) +GO +~~START~~ +datetime +2020-01-06 00:00:00.0 +~~END~~ + +~~START~~ +datetime +2020-01-07 00:00:00.0 +~~END~~ + + +SET DATEFIRST 3 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-01-12' as date)) +SELECT DATETRUNC(WEEK, CAST('2020-01-12' as date)) +GO +~~START~~ +date +2020-01-06 +~~END~~ + +~~START~~ +date +2020-01-08 +~~END~~ + + +SET DATEFIRST 4 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-01-12 12:22:32' as smalldatetime)) +SELECT DATETRUNC(WEEK, CAST('2020-01-12 21:23:23' as smalldatetime)) +GO +~~START~~ +smalldatetime +2020-01-06 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2020-01-09 00:00:00.0 +~~END~~ + + +SET DATEFIRST 5 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-01-12 12:22:32' as datetime2)) +SELECT DATETRUNC(WEEK, CAST('2020-01-12 21:23:23' as datetime2)) +GO +~~START~~ +datetime2 +2020-01-06 00:00:00.0000000 +~~END~~ + +~~START~~ +datetime2 +2020-01-10 00:00:00.0000000 +~~END~~ + + +SET DATEFIRST 6 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-01-12 12:22:32 +12:32' as datetimeoffset)) +SELECT DATETRUNC(WEEK, CAST('2020-01-12 21:23:23 -09:43' as datetimeoffset)) +GO +~~START~~ +datetimeoffset +2020-01-06 00:00:00.0000000 +12:32 +~~END~~ + +~~START~~ +datetimeoffset +2020-01-11 00:00:00.0000000 -09:43 +~~END~~ + + +SET DATEFIRST 7 +SELECT DATETRUNC(ISO_WEEK, CAST('2020-01-12 12:22:32 +12:32' as datetimeoffset)) +SELECT DATETRUNC(WEEK, CAST('2020-01-12 21:23:23 -09:43' as datetimeoffset)) +GO +~~START~~ +datetimeoffset +2020-01-06 00:00:00.0000000 +12:32 +~~END~~ + +~~START~~ +datetimeoffset +2020-01-12 00:00:00.0000000 -09:43 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4046-vu-cleanup.out b/test/JDBC/expected/BABEL-4046-vu-cleanup.out new file mode 100644 index 0000000000..82d489a026 --- /dev/null +++ b/test/JDBC/expected/BABEL-4046-vu-cleanup.out @@ -0,0 +1,23 @@ +drop VIEW babel4046; +GO + +drop VIEW babel4046_2; +GO + +drop table t; +go + +drop table t_babel4046; +go + +drop table svc_defs; +go + +drop table options_t; +go + +drop table [dbo].[t3]; +go + +drop table [dbo].[t4]; +GO diff --git a/test/JDBC/expected/BABEL-4046-vu-prepare.out b/test/JDBC/expected/BABEL-4046-vu-prepare.out new file mode 100644 index 0000000000..e6030d44fb --- /dev/null +++ b/test/JDBC/expected/BABEL-4046-vu-prepare.out @@ -0,0 +1,112 @@ +create table options_t(name varchar(30)) +insert options_t values('abc') +go +~~ROW COUNT: 1~~ + + +create table svc_defs(svc_name varchar(30)) +insert svc_defs values('def') +go +~~ROW COUNT: 1~~ + + +create table t (a varchar(30)); +go + +insert into t values ('aaa'); +go +~~ROW COUNT: 1~~ + + +insert into t values ('AAA'); +go +~~ROW COUNT: 1~~ + + +create table t_babel4046 (b varchar(30)); +go + +insert into t_babel4046 values ('a%'); +go +~~ROW COUNT: 1~~ + + +insert into t_babel4046 values ('A%'); +go +~~ROW COUNT: 1~~ + + +CREATE VIEW babel4046 as +select * from t join t_babel4046 on a like b; +GO + +CREATE VIEW babel4046_2 as +select * from t join t_babel4046 on a like 'aa%' order by 1 offset 0 ROWS;; +GO + +CREATE TABLE [dbo].[t3]( + [EMPNO] [int] NOT NULL, + [ENAME] [nvarchar](10) NULL, + [BASELOC] [nvarchar](13) NULL, + [DEPTNO] [int] NOT NULL, +PRIMARY KEY CLUSTERED +( + [EMPNO] ASC +) ON [PRIMARY]) +GO + +CREATE TABLE [dbo].[t4]( + [DEPTNO] [int] NOT NULL, + [DNAME] [nvarchar](14) NULL, + [LOC] [nvarchar](13) NULL, +PRIMARY KEY CLUSTERED +( + [DEPTNO] ASC +) ON [PRIMARY]) +GO + +INSERT [dbo].[t4] ([DEPTNO], [DNAME], [LOC]) VALUES (10, N'ACCOUNTING', N'NEW YORK') +INSERT [dbo].[t4] ([DEPTNO], [DNAME], [LOC]) VALUES (20, N'RESEARCH', N'DALLAS') +INSERT [dbo].[t4] ([DEPTNO], [DNAME], [LOC]) VALUES (30, N'SALES', N'CHICAGO') +INSERT [dbo].[t4] ([DEPTNO], [DNAME], [LOC]) VALUES (40, N'SECURITY', N'BOSTON') +INSERT [dbo].[t4] ([DEPTNO], [DNAME], [LOC]) VALUES (50, N'LEGAL', N'AUSTIN') +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7369, N'SMITH', N'BOSTON', 20) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7499, N'ALLEN', N'CHICAGO', 30) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7521, N'WARD', N'CHICAGO', 30) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7566, N'JONES', N'AUSTIN', 20) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7654, N'MARTIN', N'AUSTIN', 30) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7698, N'BLAKE', N'BOSTON', 30) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7782, N'CLARK', N'NEW YORK', 10) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7788, N'SCOTT', N'NEW YORK', 20) +INSERT [dbo].[t3] ([EMPNO], [ENAME], [BASELOC], [DEPTNO]) VALUES (7839, N'KING', N'AUSTIN', 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~~ + diff --git a/test/JDBC/expected/BABEL-4046-vu-verify.out b/test/JDBC/expected/BABEL-4046-vu-verify.out new file mode 100644 index 0000000000..f1095286e8 --- /dev/null +++ b/test/JDBC/expected/BABEL-4046-vu-verify.out @@ -0,0 +1,78 @@ + +select options_t.name + from options_t + inner join svc_defs + on options_t.name like 'UM\_%' + svc_defs.svc_name escape '\' +go +~~START~~ +varchar +~~END~~ + + +select * from babel4046; +GO +~~START~~ +varchar#!#varchar +aaa#!#a% +aaa#!#A% +AAA#!#a% +AAA#!#A% +~~END~~ + + +select * from babel4046_2; +GO +~~START~~ +varchar#!#varchar +aaa#!#a% +aaa#!#A% +AAA#!#a% +AAA#!#A% +~~END~~ + + +;with EMP_T AS ( + select empno, + ename, + CASE + WHEN baseloc LIKE 'AUS%' THEN REPLACE(baseloc,'AUSTIN','A') + WHEN baseloc LIKE 'CHI%' THEN REPLACE(baseloc,'CHICAGO','C') + WHEN baseloc LIKE 'BOS%' THEN REPLACE(baseloc,'BOSTON','B') + ELSE + baseloc + END AS baseloc, + deptno + from t3) + select + DM.empno, + DM.ename, + DM.baseloc + from EMP_T DM + INNER JOIN t4 SR ON DM.baseloc = SR.loc AND DM.deptno = SR.deptno order by DM.empno; +GO +~~START~~ +int#!#nvarchar#!#text +7782#!#CLARK#!#NEW YORK +~~END~~ + + +;with EMP_T AS ( select empno, ename, CASE WHEN baseloc LIKE 'AUS%' THEN REPLACE(baseloc,'AUSTIN','A') ELSE baseloc END AS baseloc, deptno from t3) + select DM.empno, DM.ename, DM.baseloc from EMP_T DM where DM.baseloc in (select baseloc from t4) order by DM.empno +GO +~~START~~ +int#!#nvarchar#!#text +7369#!#SMITH#!#BOSTON +7499#!#ALLEN#!#CHICAGO +7521#!#WARD#!#CHICAGO +7566#!#JONES#!#A +7654#!#MARTIN#!#A +7698#!#BLAKE#!#BOSTON +7782#!#CLARK#!#NEW YORK +7788#!#SCOTT#!#NEW YORK +7839#!#KING#!#A +~~END~~ + + + + + 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/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/expected/BABEL-4161-vu-cleanup.out b/test/JDBC/expected/BABEL-4161-vu-cleanup.out new file mode 100644 index 0000000000..7e54cd84af --- /dev/null +++ b/test/JDBC/expected/BABEL-4161-vu-cleanup.out @@ -0,0 +1,3 @@ +drop type typ4161 +go + diff --git a/test/JDBC/expected/BABEL-4161-vu-prepare.out b/test/JDBC/expected/BABEL-4161-vu-prepare.out new file mode 100644 index 0000000000..cfd6c90ea8 --- /dev/null +++ b/test/JDBC/expected/BABEL-4161-vu-prepare.out @@ -0,0 +1,2 @@ +create type typ4161 from int +go diff --git a/test/JDBC/expected/BABEL-4161-vu-verify.out b/test/JDBC/expected/BABEL-4161-vu-verify.out new file mode 100644 index 0000000000..abb8a1c4fe --- /dev/null +++ b/test/JDBC/expected/BABEL-4161-vu-verify.out @@ -0,0 +1,24 @@ +create table #t4161(c1 int, c2 int) +go + +create index i4161 on #t4161(c1) +go + +drop table #t4161 +go + +create table #t4161(c1 int, c2 int) +go + +create index i4161 on #t4161(c1) +go + +create table #t4161a (a typ4161) +go + +create index ind4161a on #t4161a(a) +go + +drop table #t4161a +go + diff --git a/test/JDBC/expected/BABEL-4168-vu-cleanup.out b/test/JDBC/expected/BABEL-4168-vu-cleanup.out new file mode 100644 index 0000000000..62bc16265c --- /dev/null +++ b/test/JDBC/expected/BABEL-4168-vu-cleanup.out @@ -0,0 +1,10 @@ +EXEC sp_dropserver 'babel_4168_server', 'droplogins' +GO + +-- psql +DROP EXTENSION IF EXISTS tds_fdw CASCADE; +GO + +-- tsql +DROP VIEW babel_4168_vu_prepare_view +GO diff --git a/test/JDBC/expected/BABEL-4168-vu-prepare.out b/test/JDBC/expected/BABEL-4168-vu-prepare.out new file mode 100644 index 0000000000..55185e07af --- /dev/null +++ b/test/JDBC/expected/BABEL-4168-vu-prepare.out @@ -0,0 +1,15 @@ +-- psql +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +-- Add localhost as linked server +EXEC sp_addlinkedserver @server = N'babel_4168_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'babel_4168_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +CREATE VIEW babel_4168_vu_prepare_view AS SELECT * FROM OPENQUERY(babel_4168_server, 'SELECT 1') +GO diff --git a/test/JDBC/expected/BABEL-4168-vu-verify.out b/test/JDBC/expected/BABEL-4168-vu-verify.out new file mode 100644 index 0000000000..840f2d19fe --- /dev/null +++ b/test/JDBC/expected/BABEL-4168-vu-verify.out @@ -0,0 +1,7 @@ +SELECT * FROM babel_4168_vu_prepare_view +GO +~~START~~ +int +1 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4175-vu-cleanup.out b/test/JDBC/expected/BABEL-4175-vu-cleanup.out new file mode 100644 index 0000000000..fb1f01119c --- /dev/null +++ b/test/JDBC/expected/BABEL-4175-vu-cleanup.out @@ -0,0 +1,5 @@ +DROP TABLE insertTest; +GO + +DROP TABLE Purchasing; +GO diff --git a/test/JDBC/expected/BABEL-4175-vu-prepare.out b/test/JDBC/expected/BABEL-4175-vu-prepare.out new file mode 100644 index 0000000000..e56bafb4b6 --- /dev/null +++ b/test/JDBC/expected/BABEL-4175-vu-prepare.out @@ -0,0 +1,33 @@ +CREATE TABLE Purchasing ( + OrderID int, + EmployeeID int, + VendorID int +); +GO + +CREATE TABLE insertTest(VendorID INT) +GO + + +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (1, 52, 158); +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (2, 44, 146); +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (3, 25, 142); +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (4, 66, 460); +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (5, 37, 154); +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (6, 53, 564); +INSERT INTO Purchasing(OrderID, EmployeeID, VendorID) VALUES (7, 36, 156); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/BABEL-4175-vu-verify.out b/test/JDBC/expected/BABEL-4175-vu-verify.out new file mode 100644 index 0000000000..a7b96f8adf --- /dev/null +++ b/test/JDBC/expected/BABEL-4175-vu-verify.out @@ -0,0 +1,98 @@ +SELECT * FROM Purchasing; +GO +~~START~~ +int#!#int#!#int +1#!#52#!#158 +2#!#44#!#146 +3#!#25#!#142 +4#!#66#!#460 +5#!#37#!#154 +6#!#53#!#564 +7#!#36#!#156 +~~END~~ + + +-- Verify DELETE TOP without parens +-- This should fail +DELETE TOP 2 FROM Purchasing; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '2' at line 3 and character position 11)~~ + + +DELETE TOP (2) FROM Purchasing; +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM Purchasing; +GO +~~START~~ +int#!#int#!#int +3#!#25#!#142 +4#!#66#!#460 +5#!#37#!#154 +6#!#53#!#564 +7#!#36#!#156 +~~END~~ + + +-- Verify UPDATE TOP without parens +-- This should fail +UPDATE TOP 2 Purchasing SET VendorID = 0; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '2' at line 3 and character position 11)~~ + + +UPDATE TOP (2) Purchasing SET VendorID = 0; +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM Purchasing; +GO +~~START~~ +int#!#int#!#int +5#!#37#!#154 +6#!#53#!#564 +7#!#36#!#156 +3#!#25#!#0 +4#!#66#!#0 +~~END~~ + + +SELECT * FROM insertTest +GO +~~START~~ +int +~~END~~ + + + +-- Verify INSERT TOP without parens +-- This should fail +INSERT TOP 3 INTO insertTest(VendorID) SELECT VendorID FROM Purchasing +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '3' at line 3 and character position 11)~~ + + +INSERT TOP (3) INTO insertTest(VendorID) SELECT VendorID FROM Purchasing +GO +~~ROW COUNT: 3~~ + + +SELECT * FROM insertTest +GO +~~START~~ +int +154 +564 +156 +~~END~~ + + diff --git a/test/JDBC/expected/BABEL-4214-vu-cleanup.out b/test/JDBC/expected/BABEL-4214-vu-cleanup.out new file mode 100644 index 0000000000..30be0d8758 --- /dev/null +++ b/test/JDBC/expected/BABEL-4214-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP PROC IF EXISTS babel_4214_datetime_to_int_proc +GO + +DROP FUNCTION IF EXISTS babel_4214_datetime_to_int_function +GO + +DROP PROC IF EXISTS babel_4214_smalldatetime_to_int_proc +GO + +DROP FUNCTION IF EXISTS babel_4214_smalldatetime_to_int_function +GO diff --git a/test/JDBC/expected/BABEL-4214-vu-prepare.out b/test/JDBC/expected/BABEL-4214-vu-prepare.out new file mode 100644 index 0000000000..178b4c17f0 --- /dev/null +++ b/test/JDBC/expected/BABEL-4214-vu-prepare.out @@ -0,0 +1,23 @@ +CREATE PROC babel_4214_datetime_to_int_proc +AS +SELECT CAST(CAST('1900-01-10 11:09:58.382' AS DATETIME) AS INT); +GO + +CREATE FUNCTION babel_4214_datetime_to_int_function() +RETURNS INT AS +BEGIN + RETURN (SELECT CAST(CAST('1900-01-10 11:09:58.382' AS DATETIME) AS INT)) +END +GO + +CREATE PROC babel_4214_smalldatetime_to_int_proc +AS +SELECT CAST(CAST('1900-01-10 11:09:58.382' AS SMALLDATETIME) AS INT); +GO + +CREATE FUNCTION babel_4214_smalldatetime_to_int_function() +RETURNS INT AS +BEGIN + RETURN (SELECT CAST(CAST('1900-01-10 11:09:58.382' AS SMALLDATETIME) AS INT)) +END +GO diff --git a/test/JDBC/expected/BABEL-4214-vu-verify.out b/test/JDBC/expected/BABEL-4214-vu-verify.out new file mode 100644 index 0000000000..3832ecca3a --- /dev/null +++ b/test/JDBC/expected/BABEL-4214-vu-verify.out @@ -0,0 +1,753 @@ +-- DATETIME cases +EXEC babel_4214_datetime_to_int_proc +GO +~~START~~ +int +9 +~~END~~ + + +SELECT babel_4214_datetime_to_int_function() +GO +~~START~~ +int +9 +~~END~~ + + +SELECT CONVERT(BIT, ISNULL(CAST('1900-01-10 11:00:50.677' AS DATETIME), 0)); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 11:00:50.699' AS DATETIME) AS FLOAT); +GO +~~START~~ +float +9.458920138888889 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 11:00:50.699' AS DATETIME) AS FLOAT) +.999999; +GO +~~START~~ +float +10.45891913888889 +~~END~~ + + +SELECT CAST(CAST(CAST('1900-01-10 11:00:50.699' AS DATETIME) AS FLOAT) AS DATETIME); +GO +~~START~~ +datetime +1900-01-10 11:00:50.7 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS TINYINT); +GO +~~START~~ +tinyint +10 +~~END~~ + + +SELECT CAST(CAST('1910-01-10 12:56:50.699' AS DATETIME) AS SMALLINT); +GO +~~START~~ +smallint +3662 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS INT); +GO +~~START~~ +int +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS BIGINT); +GO +~~START~~ +bigint +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS REAL); +GO +~~START~~ +real +9.539475 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS FLOAT); +GO +~~START~~ +float +9.539475694444445 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS DOUBLE PRECISION); +GO +~~START~~ +float +9.539475694444445 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS NUMERIC(18,4)); +GO +~~START~~ +numeric +9.5395 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +9.539476 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +9.53948 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS TINYINT); +GO +~~START~~ +tinyint +10 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS INT); +GO +~~START~~ +int +44926 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS BIGINT); +GO +~~START~~ +bigint +44926 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS REAL); +GO +~~START~~ +real +44925.54 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS FLOAT); +GO +~~START~~ +float +44925.539475694444 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS DOUBLE PRECISION); +GO +~~START~~ +float +44925.539475694444 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS NUMERIC(18,4)); +GO +~~START~~ +numeric +44925.5395 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +44925.539476 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +44925.53948 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST(CAST('1900-01-10 12:56:50.699' AS DATETIME) AS sql_variant) AS TINYINT); +GO +~~START~~ +tinyint +10 +~~END~~ + + +SELECT CAST(CAST(CAST('1910-01-10 12:56:50.699' AS DATETIME) AS sql_variant) AS SMALLINT); +GO +~~START~~ +smallint +3662 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS INT); +GO +~~START~~ +int +44926 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS BIGINT); +GO +~~START~~ +bigint +44926 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS REAL); +GO +~~START~~ +real +44925.54 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS FLOAT); +GO +~~START~~ +float +44925.539475694444 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS DOUBLE PRECISION); +GO +~~START~~ +float +44925.539475694444 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +44925.539476 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS DATETIME) AS sql_variant) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +44925.53948 +~~END~~ + + + +-- Negative dates, i.e. dates before 1900-01-01 +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1899-12-21 12:56:50.677' AS DATETIME) AS TINYINT); +GO +~~START~~ +tinyint +~~ERROR (Code: 220)~~ + +~~ERROR (Message: value for domain tinyint violates check constraint "tinyint_check")~~ + + +SELECT CAST(CAST('1890-12-21 12:56:50.677' AS DATETIME) AS SMALLINT); +GO +~~START~~ +smallint +-3297 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS INT); +GO +~~START~~ +int +-3651 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS BIGINT); +GO +~~START~~ +bigint +-3651 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS REAL); +GO +~~START~~ +real +-3651.4604 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS FLOAT); +GO +~~START~~ +float +-3651.460524421296 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS DOUBLE PRECISION); +GO +~~START~~ +float +-3651.460524421296 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS NUMERIC(18,4)); +GO +~~START~~ +numeric +-3651.4605 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +-3651.460524 +~~END~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS DATETIME) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +-3651.46052 +~~END~~ + + +-- SMALLDATETIME cases +EXEC babel_4214_smalldatetime_to_int_proc +GO +~~START~~ +int +9 +~~END~~ + + +SELECT babel_4214_smalldatetime_to_int_function(); +GO +~~START~~ +int +9 +~~END~~ + + +SELECT CONVERT(BIT, ISNULL(CAST('1900-01-10 11:00:50.699' AS SMALLDATETIME), 0)); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 11:00:50.699' AS SMALLDATETIME) AS FLOAT); +GO +~~START~~ +float +9.459027777777777 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 11:00:50.699' AS SMALLDATETIME) AS FLOAT) +.999999; +GO +~~START~~ +float +10.459026777777778 +~~END~~ + + +SELECT CAST(CAST(CAST('1900-01-10 11:00:50.699' AS SMALLDATETIME) AS FLOAT) AS SMALLDATETIME); +GO +~~START~~ +smalldatetime +1900-01-10 11:01:00.0 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS TINYINT); +GO +~~START~~ +tinyint +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS SMALLINT); +GO +~~START~~ +smallint +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS INT); +GO +~~START~~ +int +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS BIGINT); +GO +~~START~~ +bigint +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS REAL); +GO +~~START~~ +real +9.539583 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS FLOAT); +GO +~~START~~ +float +9.539583333333333 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS DOUBLE PRECISION); +GO +~~START~~ +float +9.539583333333333 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS NUMERIC); +GO +~~START~~ +numeric +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS NUMERIC(18,4)); +GO +~~START~~ +numeric +9.5396 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +9.539583 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS NUMERIC(18,10)); +GO +~~START~~ +numeric +9.5395833333 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS DECIMAL); +GO +~~START~~ +numeric +10 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +9.53958 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST('1900-01-10 12:56:50.699' AS SMALLDATETIME) AS TINYINT); +GO +~~START~~ +tinyint +10 +~~END~~ + + +SELECT CAST(CAST('1910-01-10 12:56:50.699' AS SMALLDATETIME) AS SMALLINT); +GO +~~START~~ +smallint +3662 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS INT); +GO +~~START~~ +int +44926 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS BIGINT); +GO +~~START~~ +bigint +44926 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS REAL); +GO +~~START~~ +real +44925.54 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS FLOAT); +GO +~~START~~ +float +44925.53958333333 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS DOUBLE PRECISION); +GO +~~START~~ +float +44925.53958333333 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS NUMERIC); +GO +~~START~~ +numeric +44926 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS NUMERIC(18,4)); +GO +~~START~~ +numeric +44925.5396 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +44925.539583 +~~END~~ + + +SELECT CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +44925.53958 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS BIT); +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT CAST(CAST(CAST('1900-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS TINYINT); +GO +~~START~~ +tinyint +1 +~~END~~ + + +SELECT CAST(CAST(CAST('1910-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS SMALLINT); +GO +~~START~~ +smallint +3653 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS INT); +GO +~~START~~ +int +44926 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS BIGINT); +GO +~~START~~ +bigint +44926 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS REAL); +GO +~~START~~ +real +44925.54 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS FLOAT); +GO +~~START~~ +float +44925.53958333333 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS DOUBLE PRECISION); +GO +~~START~~ +float +44925.53958333333 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS NUMERIC(18,6)); +GO +~~START~~ +numeric +44925.539583 +~~END~~ + + +SELECT CAST(CAST(CAST('2023-01-01 12:56:50.699' AS SMALLDATETIME) AS sql_variant) AS DECIMAL(18,5)); +GO +~~START~~ +numeric +44925.53958 +~~END~~ + + +-- Negative dates are not supported by SMALLDATETIME, i.e. dates before 1900-01-01 +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS SMALLDATETIME) AS INT); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS SMALLDATETIME) AS BIGINT); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS SMALLDATETIME) AS FLOAT); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + +SELECT CAST(CAST('1890-01-01 12:56:50.677' AS SMALLDATETIME) AS NUMERIC(18,6)); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + diff --git a/test/JDBC/expected/BABEL-4217-vu-cleanup.out b/test/JDBC/expected/BABEL-4217-vu-cleanup.out new file mode 100644 index 0000000000..8d8c0835a2 --- /dev/null +++ b/test/JDBC/expected/BABEL-4217-vu-cleanup.out @@ -0,0 +1,31 @@ +drop table BABEL_4217_vu_prepare_t1; +go +drop table BABEL_4217_vu_prepare_t2; +go +drop table BABEL_4217_vu_prepare_t3; +go +drop table BABEL_4217_vu_prepare_t4; +go +drop table BABEL_4217_vu_prepare_t5; +go +drop table BABEL_4217_vu_prepare_t6; +go +drop table BABEL_4217_vu_prepare_t7; +go +drop table BABEL_4217_vu_prepare_t8; +go +drop table BABEL_4217_vu_prepare_t9; +go +drop table BABEL_4217_vu_prepare_t10; +go +drop table BABEL_4217_vu_prepare_t11; +go +drop table BABEL_4217_vu_prepare_t12; +go +drop table BABEL_4217_vu_prepare_t13; +go +drop table BABEL_4217_vu_prepare_t14; +go +drop table BABEL_4217_vu_prepare_t15; +go + diff --git a/test/JDBC/expected/BABEL-4217-vu-prepare.out b/test/JDBC/expected/BABEL-4217-vu-prepare.out new file mode 100644 index 0000000000..aa00ca6bd9 --- /dev/null +++ b/test/JDBC/expected/BABEL-4217-vu-prepare.out @@ -0,0 +1,216 @@ +-- Used PRIMARY KEY & Placed NOT NULL before Identity Column +CREATE TABLE BABEL_4217_vu_prepare_t1 ( + ID INT PRIMARY KEY NOT NULL IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t1 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY & Placed NOT NULL after Identity Column +CREATE TABLE BABEL_4217_vu_prepare_t2 ( + ID INT PRIMARY KEY IDENTITY(1,1) NOT NULL, + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t2 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY & Placed NOT NULL before PRIMARY KEY +CREATE TABLE BABEL_4217_vu_prepare_t3 ( + ID INT NOT NULL PRIMARY KEY IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t3 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql) and placed not null after identity column +CREATE TABLE BABEL_4217_vu_prepare_t4 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t4 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql) and placed not null before identity column +CREATE TABLE BABEL_4217_vu_prepare_t5 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t5 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql) and placed not null before primary key +CREATE TABLE BABEL_4217_vu_prepare_t6 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t6 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used UNIQUE & Placed NOT NULL before Identity Column +CREATE TABLE BABEL_4217_vu_prepare_t7 ( + ID INT UNIQUE NOT NULL IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t7 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used UNIQUE & Placed NOT NULL after Identity Column +CREATE TABLE BABEL_4217_vu_prepare_t8 ( + ID INT UNIQUE IDENTITY(1,1) NOT NULL, + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t8 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used UNIQUE & Placed NOT NULL before PRIMARY KEY +CREATE TABLE BABEL_4217_vu_prepare_t9 ( + ID INT NOT NULL UNIQUE IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t9 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used UNIQUE & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql) and placed not null after identity column +CREATE TABLE BABEL_4217_vu_prepare_t10 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t10 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used UNIQUE & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql) and placed not null before identity column +CREATE TABLE BABEL_4217_vu_prepare_t11 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t11 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used UNIQUE & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql) and placed not null before UNIQUE Constraint +CREATE TABLE BABEL_4217_vu_prepare_t12 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t12 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY, placed NOT NULL before Identity Column & added a check constraint before identity column +CREATE TABLE BABEL_4217_vu_prepare_t13 ( + ID INT PRIMARY KEY NOT NULL CHECK(ID < 5) IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t13 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY, placed NOT NULL before Identity Column & added default constraint before identity column (it should give error) +CREATE TABLE BABEL_4217_vu_prepare_t14 ( + ID INT PRIMARY KEY NOT NULL DEFAULT 0 IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: both default and identity specified for column "id" of table "babel_4217_vu_prepare_t14")~~ + + +-- Used PRIMARY KEY & Created Table first and then use alter table(in BABEL-4217-vu-verify.sql), placed not null before identity column and added 'check' & 'default' constraint before identity column +CREATE TABLE BABEL_4217_vu_prepare_t14 ( + FIRSTNAME VARCHAR(50) +); +GO + +INSERT INTO BABEL_4217_vu_prepare_t14 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ROW COUNT: 2~~ + + +-- Used PRIMARY KEY, placed NOT NULL before Identity Column & added a check constraint before identity column +CREATE TABLE BABEL_4217_vu_prepare_t15 ( + ID INT PRIMARY KEY NOT NULL CHECK(ID > 2) IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO + +-- It should give error (check constraint violation) +INSERT INTO BABEL_4217_vu_prepare_t15 (FIRSTNAME) +VALUES ('John'), + ('Jane'); +GO +~~ERROR (Code: 547)~~ + +~~ERROR (Message: new row for relation "babel_4217_vu_prepare_t15" violates check constraint "babel_4217_vu_prepare_t15_id_check")~~ + diff --git a/test/JDBC/expected/BABEL-4217-vu-verify.out b/test/JDBC/expected/BABEL-4217-vu-verify.out new file mode 100644 index 0000000000..6c112e3dc6 --- /dev/null +++ b/test/JDBC/expected/BABEL-4217-vu-verify.out @@ -0,0 +1,294 @@ +--INSERT BULK queries are no-op query, we are just handling the syntax from antlr parser side. +SELECT * FROM BABEL_4217_vu_prepare_t1; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t1 ( + ID INT PRIMARY KEY NOT NULL IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t1; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t2; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t2 ( + ID INT PRIMARY KEY IDENTITY(1,1) NOT NULL, + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t2; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t3; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t3 ( + ID INT NOT NULL PRIMARY KEY IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t3; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t4; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +ALTER TABLE BABEL_4217_vu_prepare_t4 add id INT PRIMARY KEY IDENTITY(1,1) NOT NULL; +GO +SELECT * FROM BABEL_4217_vu_prepare_t4; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t5; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +ALTER TABLE BABEL_4217_vu_prepare_t5 add id INT PRIMARY KEY NOT NULL IDENTITY(1,1); +GO +SELECT * FROM BABEL_4217_vu_prepare_t5; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t6; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +ALTER TABLE BABEL_4217_vu_prepare_t6 add id INT NOT NULL PRIMARY KEY IDENTITY(1,1); +GO +SELECT * FROM BABEL_4217_vu_prepare_t6; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t7; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t7 ( + ID INT UNIQUE NOT NULL IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t7; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t8; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t8 ( + ID INT UNIQUE IDENTITY(1,1) NOT NULL, + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t8; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t9; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t9 ( + ID INT NOT NULL UNIQUE IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t9; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t10; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +ALTER TABLE BABEL_4217_vu_prepare_t10 add id INT UNIQUE IDENTITY(1,1) NOT NULL; +GO +SELECT * FROM BABEL_4217_vu_prepare_t10; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t11; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +ALTER TABLE BABEL_4217_vu_prepare_t11 add id INT UNIQUE NOT NULL IDENTITY(1,1); +GO +SELECT * FROM BABEL_4217_vu_prepare_t11; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t12; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +ALTER TABLE BABEL_4217_vu_prepare_t12 add id INT NOT NULL UNIQUE IDENTITY(1,1); +GO +SELECT * FROM BABEL_4217_vu_prepare_t12; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t13; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + +INSERT BULK BABEL_4217_vu_prepare_t13 ( + ID INT PRIMARY KEY NOT NULL CHECK(ID < 5) IDENTITY(1,1), + FIRSTNAME VARCHAR(50) +); +GO +SELECT * FROM BABEL_4217_vu_prepare_t13; +GO +~~START~~ +int#!#varchar +1#!#John +2#!#Jane +~~END~~ + + +SELECT * FROM BABEL_4217_vu_prepare_t14; +GO +~~START~~ +varchar +John +Jane +~~END~~ + +-- It should give error (default and identity cannot be assigned to same column) +ALTER TABLE BABEL_4217_vu_prepare_t14 add id INT PRIMARY KEY NOT NULL DEFAULT 0 IDENTITY(1,1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: both default and identity specified for column "id" of table "babel_4217_vu_prepare_t14")~~ + +ALTER TABLE BABEL_4217_vu_prepare_t14 add id INT PRIMARY KEY NOT NULL CHECK(id < 5) IDENTITY(1,1); +GO +SELECT * FROM BABEL_4217_vu_prepare_t14; +GO +~~START~~ +varchar#!#int +John#!#1 +Jane#!#2 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4231-vu-cleanup.out b/test/JDBC/expected/BABEL-4231-vu-cleanup.out new file mode 100644 index 0000000000..c949c9b902 --- /dev/null +++ b/test/JDBC/expected/BABEL-4231-vu-cleanup.out @@ -0,0 +1,159 @@ +-- tsql +DROP VIEW view_babel_4231_1; +GO + +DROP VIEW view_babel_4231_2; +GO + +DROP VIEW view_babel_4231_3; +GO + +DROP VIEW view_babel_4231_4; +GO + +DROP VIEW view_babel_4231_5; +GO + +DROP VIEW view_babel_4231_6; +GO + +DROP VIEW view_babel_4231_7; +GO + +DROP VIEW view_babel_4231_8; +GO + +DROP VIEW view_babel_4231_9; +GO + +DROP VIEW view_babel_4231_10; +GO + +DROP VIEW view_babel_4231_11; +GO + +DROP VIEW view_babel_4231_12; +GO + +DROP VIEW view_babel_4231_13; +GO + +DROP VIEW view_babel_4231_14; +GO + +DROP VIEW view_babel_4231_15; +GO + +DROP VIEW view_babel_4231_16; +GO + +DROP VIEW view_babel_4231_17; +GO + +DROP VIEW view_babel_4231_18; +GO + +DROP VIEW view_babel_4231_19; +GO +DROP TABLE table1_babel_4231; +GO + +DROP VIEW view_babel_4231_20; +GO +DROP TABLE table2_babel_4231; +GO + +DROP VIEW view_babel_4231_21; +GO +DROP TABLE table3_babel_4231; +GO + +DROP VIEW view_babel_4231_22; +GO +DROP TABLE table4_babel_4231; +GO + +DROP VIEW view_babel_4231_23; +GO +DROP TABLE table5_babel_4231; +GO + +DROP VIEW view_babel_4231_24; +GO +DROP TABLE table6_babel_4231; +GO + +DROP VIEW view_babel_4231_25; +GO +DROP TABLE table7_babel_4231; +GO + +DROP VIEW view_babel_4231_26; +GO +DROP TABLE table8_babel_4231; +GO + +DROP VIEW view_babel_4231_27; +GO +DROP TABLE table9_babel_4231; +GO + +DROP VIEW view_babel_4231_28; +GO +DROP TABLE table10_babel_4231; +GO + +DROP VIEW view_babel_4231_29; +GO +DROP TABLE table11_babel_4231; +GO + +DROP VIEW view_babel_4231_30; +GO +DROP TABLE table12_babel_4231; +GO + +DROP VIEW view_babel_4231_31; +GO +DROP TABLE table13_babel_4231; +GO + +DROP VIEW view_babel_4231_32; +GO +DROP TABLE table14_babel_4231; +GO + +DROP VIEW view_babel_4231_33; +GO +DROP TABLE table15_babel_4231; +GO + +DROP VIEW view_babel_4231_34; +GO +DROP TABLE table16_babel_4231; +GO + +DROP VIEW view_babel_4231_35; +GO +DROP TABLE table17_babel_4231; +GO + +DROP VIEW view_babel_4231_36; +GO + +DROP VIEW view_babel_4231_37; +GO + +DROP VIEW view_babel_4231_38; +GO + +DROP VIEW view_babel_4231_39; +GO + +DROP VIEW view_babel_4231_40; +GO +DROP TABLE table18_babel_4231; +GO + +DROP VIEW view_babel_4231_41; +GO diff --git a/test/JDBC/expected/BABEL-4231-vu-prepare.out b/test/JDBC/expected/BABEL-4231-vu-prepare.out new file mode 100644 index 0000000000..a2a9664c5d --- /dev/null +++ b/test/JDBC/expected/BABEL-4231-vu-prepare.out @@ -0,0 +1,270 @@ +-- tsql +-- column aliases with english characters whose length is less than 64 +CREATE VIEW view_babel_4231_1 AS SELECT 1 AS "AbcdE"; +GO + +-- tsql +-- column aliases with english characters whose length is more than or equals 64 +CREATE VIEW view_babel_4231_2 AS SELECT 1 AS "AbnkxalnclKSNcfjNAJCb jdsb;FCBouiwehyriuoqjhINCKSJBDCJS csjkndbcjsdbcjsNDJFKWcdE"; +GO + +-- tsql +-- column aliases with english characters whose length is more than or equals 64 +CREATE VIEW view_babel_4231_3 AS SELECT 1 AS [AbnkxalnclKSNcfjNAJCb jdsb;FCBouiwehyriuoqjhINCKSJBDCJS csjkndbcjsdbcjsND]; +GO + + +-- tsql +-- column aliases with chinese characters whose length is less than 64 +CREATE VIEW view_babel_4231_4 AS SELECT 1 AS "您对“数"; +GO + + +-- tsql +-- column aliases with chinese characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_5 AS SELECT 1 AS "您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装, "; +GO + + +-- tsql +-- column aliases with chinese characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_6 AS SELECT 1 AS [您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装, ]; +GO + + +-- tsql +-- column aliases with japanese characters whose length is less than 64 +CREATE VIEW view_babel_4231_7 AS SELECT 1 AS " ã ã‚ "; +GO + + +-- tsql +-- column aliases with japanese characters whose length is less than 64 +CREATE VIEW view_babel_4231_8 AS SELECT 1 AS [ã ã‚ ]; +GO + + +-- tsql +-- column aliases with japanese characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_9 AS SELECT 1 AS " ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ ã‰ ã› ãœ ã™ ã˜ ã— ã– ã• ã‚‘ ス ウ ã‚Ž ãº"; +GO + +-- tsql +-- column aliases with korean characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_10 AS SELECT 1 AS "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡ ã…ˆ ã…Š ã…‹ ã…Œ ã… ã…Žã… ã…‘ ã…“ ã…• ã…— ã…› ã…œ ã…  ã…¡ ã…£"; +GO + + +-- tsql +-- column aliases with korean characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_11 AS SELECT 1 AS [ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡ ã…ˆ ã…Š ã…‹ ã…Œ ã… ã…Žã… ã…‘ ã…“ ã…• ã…— ã…› ã…œ ã…  ã…¡ ã…£]; +GO + + +-- tsql +-- column aliases with korean characters whose length is less than 64 +CREATE VIEW view_babel_4231_12 AS SELECT 1 AS "ã„´ ã„· ㄹ ã…"; +GO + + +-- tsql +-- column aliases with arabic characters whose length is less than 64 +CREATE VIEW view_babel_4231_13 AS SELECT 1 AS "Ø® Ø° ض ظ"; +GO + + +-- tsql +-- column aliases with arabic characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_14 AS SELECT 1 AS "ج د Ù‡ Ùˆ ز Ø­ Ø· ÙŠ Ùƒ Ù„ Ù… Ù† س ع ٠ص Ù‚ ر Ø´ ت Ø« Ø® Ø° ض ظ غ"; +GO + + +-- tsql +-- column aliases with polish characters whose length is less than 64 +CREATE VIEW view_babel_4231_15 AS SELECT 1 AS [ĄĆĘÅŃÓŚŹŻąćęłńóśź]; +GO + + +-- tsql +-- column aliases with polish characters whose length is less than 64 +CREATE VIEW view_babel_4231_16 AS SELECT 1 AS "ĄĆĘÅŃÓŚŹŻąćęłńóśź"; +GO + + +-- tsql +-- column aliases with greek characters whose length is less than 64 +CREATE VIEW view_babel_4231_17 AS SELECT 1 AS "αΒβΓγΔδΕε"; +GO + + +-- tsql +-- column aliases with greek characters whose length is greater than or equals to 64 +CREATE VIEW view_babel_4231_18 AS SELECT 1 AS "αΒβΓγΔδΕεΖζ ΗηΘΙιΚ κ, Λ λ, Îœ μ, Πν, Ξ ξ, Ο ο, Π Ï€, Ρ Ï, Σ σ/Ï‚, Τ Ï„, Î¥ Ï…, Φ φ, Χ χ, Ψ ψ"; +GO + + +-- tsql +-- table aliases with english characters whose length is less than 64 +CREATE TABLE table1_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_19 AS SELECT * FROM table1_babel_4231 as "abndand_dkandf"""; +GO + + +-- tsql +-- table aliases with english characters whose length is more than or equals 64 +CREATE TABLE table2_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_20 AS SELECT * FROM table2_babel_4231 AS "AbnkxalnclKSNcfjNAJCb jdsb;FCBouiwehyriuoqjhINCKSJBDCJS csjkndbcjsdbcjsNDJFKWcdE"; +GO + + +-- tsql +-- table aliases with chinese characters whose length is less than 64 +CREATE TABLE table3_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_21 AS SELECT * FROM table3_babel_4231 AS "您对数"; +GO + + +-- tsql +-- table aliases with chinese characters whose length is less than 64 +CREATE TABLE table4_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_22 AS SELECT * FROM table4_babel_4231 AS [您对数]; +GO + + +-- tsql +-- table aliases with chinese characters whose length is greater than or equals to 64 +CREATE TABLE table5_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_23 AS SELECT * FROM table5_babel_4231 AS "您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装"; +GO + + +-- tsql +-- table aliases with japanese characters whose length is less than 64 +CREATE TABLE table6_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_24 AS SELECT * FROM table6_babel_4231 AS " ã ã‚"; +GO + + +-- tsql +-- table aliases with japanese characters whose length is more than or equals to 64 +CREATE TABLE table7_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_25 AS SELECT * FROM table7_babel_4231 AS "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ ã‰ ã› ãœ ã™ ã˜ ã— ã– ã• ã‚‘ ス ウ ã‚Ž ãº"; +GO + + +-- tsql +-- table aliases with japanese characters whose length is more than or equals to 64 +CREATE TABLE table8_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_26 AS SELECT * FROM table8_babel_4231 AS [ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ ã‰ ã› ãœ ã™ ã˜ ã— ã– ã• ã‚‘ ス ウ ã‚Ž ãº]; +GO + + +-- tsql +-- table aliases with korean characters whose length is less than 64 +CREATE TABLE table9_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_27 AS SELECT * FROM table9_babel_4231 AS "ㄱ ã„´ ã„· ㄹ"; +GO + + +-- tsql +-- table aliases with korean characters whose length is less than 64 +CREATE TABLE table10_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_28 AS SELECT * FROM table10_babel_4231 AS [ㄱ ã„´ ã„· ㄹ]; +GO + + +-- tsql +-- table aliases with korean characters whose length is more than or equals to 64 +CREATE TABLE table11_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_29 AS SELECT * FROM table11_babel_4231 AS "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡ ã…ˆ ã…Š ã…‹ ã…Œ ã… ã…Žã… ã…‘ ã…“ ã…• ã…— ã…› ã…œ ã…  ã…¡ ã…£"; +GO + +-- tsql +-- table aliases with arabic characters whose length is less than 64 +CREATE TABLE table12_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_30 AS SELECT * FROM table12_babel_4231 AS "Ø® Ø° ض ظ"; +GO + + +-- tsql +-- table aliases with arabic characters whose length is more than or equals to 64 +CREATE TABLE table13_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_31 AS SELECT * FROM table13_babel_4231 AS "ج د Ù‡ Ùˆ ز Ø­ Ø· ÙŠ Ùƒ Ù„ Ù… Ù† س ع ٠ص Ù‚ ر Ø´ ت Ø« Ø® Ø° ض ظ غ"; +GO + + +-- tsql +-- table aliases with polish characters whose length is less than 64 +CREATE TABLE table14_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_32 AS SELECT * FROM table14_babel_4231 AS "ĄĆĘÅŃÓŚŹŻąćęłńóśź"; +GO + + +-- tsql +-- table aliases with greek characters whose length is less than 64 +CREATE TABLE table15_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_33 AS SELECT * FROM table15_babel_4231 AS "αΒβΓγΔδΕε"; +GO + + +-- tsql +-- table aliases with greek characters whose length is less than 64 +CREATE TABLE table16_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_34 AS SELECT * FROM table16_babel_4231 AS [αΒβΓγΔδΕε]; +GO + + +-- tsql +-- table aliases with greek characters whose length is more than or equals to 64 +CREATE TABLE table17_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_35 AS SELECT * FROM table17_babel_4231 AS "αΒβΓγΔδΕεΖζ ΗηΘΙιΚ κ, Λ λ, Îœ μ, Πν, Ξ ξ, Ο ο, Π Ï€, Ρ Ï, Σ σ/Ï‚, Τ Ï„, Î¥ Ï…, Φ φ, Χ χ, Ψ ψ"; +GO + +-- tsql +-- column aliases which are not delimited by double quote, square bracket and length is less than 64 +CREATE VIEW view_babel_4231_36 AS SELECT 1 AS ABCD; +GO + +-- tsql +-- column aliases with single byte characters which are not delimited by double quote, square bracket and length is more than or equals to 64 +CREATE VIEW view_babel_4231_37 AS SELECT 1 AS ABCDbdjaBFWFGRUWlgrefwfiwuegfdvfwefgvggfedfudywtitewutgfdWUIF; +GO + +-- tsql +-- column aliases with single byte characters which are delimited by single quote and length is more than or equals to 64 +CREATE VIEW view_babel_4231_38 AS SELECT 1 AS 'ABCDbdjaBFWFGRUWlgrefwfiwuegfdvfwefgvggfedfudywtitewutgfdWUIF'; +GO + +-- tsql +-- column aliases with single byte characters which are delimited by single quote and length is less than 64 +CREATE VIEW view_babel_4231_39 AS SELECT 1 AS N'ANfjws'; +GO + +-- tsql +-- table aliases with chinese characters whose length is more than or equals to 64 +CREATE TABLE table18_babel_4231(a INT , b INT); +GO +CREATE VIEW view_babel_4231_40 AS SELECT 您您对您对您对您对您对您对您对您对您对您您您.* FROM table18_babel_4231 AS 您您对您对您对您对您对您对您对您对您对您您您; +GO + +-- tsql +-- column aliases with multibyte characters which are delimited by single quote and length is more than 128 +CREATE VIEW view_babel_4231_41 AS SELECT 1 AS '您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装, 您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装,您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装,您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装,'; +GO diff --git a/test/JDBC/expected/BABEL-4231-vu-verify.out b/test/JDBC/expected/BABEL-4231-vu-verify.out new file mode 100644 index 0000000000..895108d30f --- /dev/null +++ b/test/JDBC/expected/BABEL-4231-vu-verify.out @@ -0,0 +1,377 @@ +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_1'; +GO +~~START~~ +text + SELECT 1 AS "AbcdE"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_2'; +GO +~~START~~ +text + SELECT 1 AS "AbnkxalnclKSNcfjNAJCb jdsb;FCBo3230b498a93d3d3c201b75df000f7422"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_3'; +GO +~~START~~ +text + SELECT 1 AS "AbnkxalnclKSNcfjNAJCb jdsb;FCBo98276e81604b6c8f5b25ae3f87180e62"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_4'; +GO +~~START~~ +text + SELECT 1 AS "您对“数"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_5'; +GO +~~START~~ +text + SELECT 1 AS "您对“数æ®ä¸€è§ˆâ€œä¸­çš„f14d4ea72c5ab09dd327efc75f66d708"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_6'; +GO +~~START~~ +text + SELECT 1 AS "您对“数æ®ä¸€è§ˆâ€œä¸­çš„f14d4ea72c5ab09dd327efc75f66d708"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_7'; +GO +~~START~~ +text + SELECT 1 AS " ã ã‚ "; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_8'; +GO +~~START~~ +text + SELECT 1 AS "ã ã‚ "; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_9'; +GO +~~START~~ +text + SELECT 1 AS " ã ã‚ ãƒ ã„ ã… ã† ã‡ 837c554dda804e3ffe7d700d76c55bc0"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_10'; +GO +~~START~~ +text + SELECT 1 AS "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡8522e1e3c9eb50a92076a5c0c105a0d6"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_11'; +GO +~~START~~ +text + SELECT 1 AS "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡8522e1e3c9eb50a92076a5c0c105a0d6"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_12'; +GO +~~START~~ +text + SELECT 1 AS "ã„´ ã„· ㄹ ã…"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_13'; +GO +~~START~~ +text + SELECT 1 AS "Ø® Ø° ض ظ"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_14'; +GO +~~START~~ +text + SELECT 1 AS "ج د Ù‡ Ùˆ ز Ø­ Ø· ÙŠ Ùƒ Ù„ 17a5c50aadee4e5fc6ccb1f1f70dd4f8"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_15'; +GO +~~START~~ +text + SELECT 1 AS "ĄĆĘÅŃÓŚŹŻąćęłńóśź"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_16'; +GO +~~START~~ +text + SELECT 1 AS "ĄĆĘÅŃÓŚŹŻąćęłńóśź"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_17'; +GO +~~START~~ +text + SELECT 1 AS "αΒβΓγΔδΕε"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_18'; +GO +~~START~~ +text + SELECT 1 AS "αΒβΓγΔδΕεΖζ ΗηΘΙc65025c8691f705f084f6d40aa6e076c"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_19'; +GO +~~START~~ +text + SELECT "abndand_dkandf""".a, "abndand_dkandf""".b FROM master_dbo.table1_babel_4231 "abndand_dkandf"""; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_20'; +GO +~~START~~ +text + SELECT "abnkxalnclksncfjnajcb jdsb;fcbo3230b498a93d3d3c201b75df000f7422".a, "abnkxalnclksncfjnajcb jdsb;fcbo3230b498a93d3d3c201b75df000f7422".b FROM master_dbo.table2_babel_4231 "abnkxalnclksncfjnajcb jdsb;fcbo3230b498a93d3d3c201b75df000f7422"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_21'; +GO +~~START~~ +text + SELECT "您对数".a, "您对数".b FROM master_dbo.table3_babel_4231 "您对数"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_22'; +GO +~~START~~ +text + SELECT "您对数".a, "您对数".b FROM master_dbo.table4_babel_4231 "您对数"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_23'; +GO +~~START~~ +text + SELECT "您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装".a, "您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装".b FROM master_dbo.table5_babel_4231 "您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_24'; +GO +~~START~~ +text + SELECT " ã ã‚".a, " ã ã‚".b FROM master_dbo.table6_babel_4231 " ã ã‚"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_25'; +GO +~~START~~ +text + SELECT "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ0ee571349edc4237ec58683730cf1445".a, "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ0ee571349edc4237ec58683730cf1445".b FROM master_dbo.table7_babel_4231 "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ0ee571349edc4237ec58683730cf1445"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_26'; +GO +~~START~~ +text + SELECT "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ0ee571349edc4237ec58683730cf1445".a, "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ0ee571349edc4237ec58683730cf1445".b FROM master_dbo.table8_babel_4231 "ã ã‚ ãƒ ã„ ã… ã† ã‡ ãˆ0ee571349edc4237ec58683730cf1445"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_27'; +GO +~~START~~ +text + SELECT "ㄱ ã„´ ã„· ㄹ".a, "ㄱ ã„´ ã„· ㄹ".b FROM master_dbo.table9_babel_4231 "ㄱ ã„´ ã„· ㄹ"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_28'; +GO +~~START~~ +text + SELECT "ㄱ ã„´ ã„· ㄹ".a, "ㄱ ã„´ ã„· ㄹ".b FROM master_dbo.table10_babel_4231 "ㄱ ã„´ ã„· ㄹ"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_29'; +GO +~~START~~ +text + SELECT "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡8522e1e3c9eb50a92076a5c0c105a0d6".a, "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡8522e1e3c9eb50a92076a5c0c105a0d6".b FROM master_dbo.table11_babel_4231 "ㄱ ã„´ ã„· ㄹ ã… ã…‚ ã…… ã…‡8522e1e3c9eb50a92076a5c0c105a0d6"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_30'; +GO +~~START~~ +text + SELECT "Ø® Ø° ض ظ".a, "Ø® Ø° ض ظ".b FROM master_dbo.table12_babel_4231 "Ø® Ø° ض ظ"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_31'; +GO +~~START~~ +text + SELECT "ج د Ù‡ Ùˆ ز Ø­ Ø· ÙŠ Ùƒ Ù„ 17a5c50aadee4e5fc6ccb1f1f70dd4f8".a, "ج د Ù‡ Ùˆ ز Ø­ Ø· ÙŠ Ùƒ Ù„ 17a5c50aadee4e5fc6ccb1f1f70dd4f8".b FROM master_dbo.table13_babel_4231 "ج د Ù‡ Ùˆ ز Ø­ Ø· ÙŠ Ùƒ Ù„ 17a5c50aadee4e5fc6ccb1f1f70dd4f8"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_32'; +GO +~~START~~ +text + SELECT "ĄĆĘÅŃÓŚŹŻąćęłńóśź".a, "ĄĆĘÅŃÓŚŹŻąćęłńóśź".b FROM master_dbo.table14_babel_4231 "ĄĆĘÅŃÓŚŹŻąćęłńóśź"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_33'; +GO +~~START~~ +text + SELECT "αΒβΓγΔδΕε".a, "αΒβΓγΔδΕε".b FROM master_dbo.table15_babel_4231 "αΒβΓγΔδΕε"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_34'; +GO +~~START~~ +text + SELECT "αΒβΓγΔδΕε".a, "αΒβΓγΔδΕε".b FROM master_dbo.table16_babel_4231 "αΒβΓγΔδΕε"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_35'; +GO +~~START~~ +text + SELECT "αΒβΓγΔδΕεΖζ ΗηΘΙc65025c8691f705f084f6d40aa6e076c".a, "αΒβΓγΔδΕεΖζ ΗηΘΙc65025c8691f705f084f6d40aa6e076c".b FROM master_dbo.table17_babel_4231 "αΒβΓγΔδΕεΖζ ΗηΘΙc65025c8691f705f084f6d40aa6e076c"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_36'; +GO +~~START~~ +text + SELECT 1 AS "ABCD"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_37'; +GO +~~START~~ +text + SELECT 1 AS "ABCDbdjaBFWFGRUWlgrefwfiwuegfdvfwefgvggfedfudywtitewutgfdWUIF"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_38'; +GO +~~START~~ +text + SELECT 1 AS "ABCDbdjaBFWFGRUWlgrefwfiwuegfdvfwefgvggfedfudywtitewutgfdWUIF"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_39'; +GO +~~START~~ +text + SELECT 1 AS "ANfjws"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_40'; +GO +~~START~~ +text + SELECT "您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de".a, "您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de".b FROM master_dbo.table18_babel_4231 "您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de"; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'view_babel_4231_41'; +GO +~~START~~ +text + SELECT 1 AS "您对“数æ®ä¸€è§ˆâ€œä¸­çš„e06f302024afe951b33a0978fde84988"; +~~END~~ + + +-- tsql +select 1 as '您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装, 您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装,您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装,您对“数æ®ä¸€è§ˆâ€œä¸­çš„车型,颜色,内饰,选装,'; +GO +~~START~~ +int +1 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4261.out b/test/JDBC/expected/BABEL-4261.out new file mode 100644 index 0000000000..e860084983 --- /dev/null +++ b/test/JDBC/expected/BABEL-4261.out @@ -0,0 +1,83 @@ +CREATE TABLE t1_babel4261 (a money); +GO + +BEGIN TRAN BABEL4261_T1; +GO + +ALTER TABLE t1_babel4261 SET (parallel_workers = 16); -- note: this is PG syntax, not T-SQL +GO + +-- The third parameter is true to set config back to default after transaction is committed +SELECT set_config('force_parallel_mode', '1', true) +SELECT set_config('parallel_setup_cost', '0', true) +SELECT set_config('parallel_tuple_cost', '0', true) +GO +~~START~~ +text +on +~~END~~ + +~~START~~ +text +0 +~~END~~ + +~~START~~ +text +0 +~~END~~ + + +--- INSERT SOME data into t1_babel4261 +INSERT t1_babel4261 SELECT 0.4245*10000 +INSERT t1_babel4261 SELECT 0.5234*10000 +INSERT t1_babel4261 SELECT 0.1113*10000 +INSERT t1_babel4261 SELECT 0.6732*10000 +INSERT t1_babel4261 SELECT 0.3467*10000 +INSERT t1_babel4261 SELECT 0.5213*10000 +INSERT t1_babel4261 SELECT 0.9893*10000 +INSERT t1_babel4261 SELECT 0.6034*10000 +INSERT t1_babel4261 SELECT 0.3334*10000 +INSERT t1_babel4261 SELECT 0.8888*10000 +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~~ + + +SELECT sum(a) FROM t1_babel4261 +SELECT sum(a) FROM t1_babel4261 -- should not crash +GO +~~START~~ +money +54153.0000 +~~END~~ + +~~START~~ +money +54153.0000 +~~END~~ + + +-- Commiting sets force_parallel_mode, parallel_setup_cost, parallel_tuple_cost back to default +COMMIT TRAN BABEL4261_T1; +GO + +DROP TABLE t1_babel4261; +GO diff --git a/test/JDBC/expected/BABEL-4264.out b/test/JDBC/expected/BABEL-4264.out new file mode 100644 index 0000000000..fb4e557643 --- /dev/null +++ b/test/JDBC/expected/BABEL-4264.out @@ -0,0 +1,281 @@ +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +create table babel4264(name1 varchar(42), flag1 bit) +go + +insert into babel4264 values ('true', 1) +insert into babel4264 values ('false', 0) +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select * from babel4264 where flag1 = CAST('true' as VARCHAR(20)) +go +~~START~~ +varchar#!#bit +true#!#1 +~~END~~ + + +select * from babel4264 where CAST('true' as VARCHAR(20)) = flag1 +go +~~START~~ +varchar#!#bit +true#!#1 +~~END~~ + + +select * from babel4264 where -flag1 = CAST('true' as VARCHAR(20)) +go +~~START~~ +varchar#!#bit +false#!#0 +~~END~~ + + +select * from babel4264 where CAST('true' as VARCHAR(20)) = ~flag1 +go +~~START~~ +varchar#!#bit +false#!#0 +~~END~~ + + +set babelfish_showplan_all on +go + +select * from babel4264 where flag1 = CAST('true' as VARCHAR(20)) +go +~~START~~ +text +Query Text: select * from babel4264 where flag1 = CAST('true' as VARCHAR(20)) +Seq Scan on babel4264 + Filter: (flag1 = '1'::"bit") +~~END~~ + + +set babelfish_showplan_all off +go + +drop table babel4264 +go + +create table babel4264(date1 date) +go + +set babelfish_showplan_all on +go + +SELECT * from babel4264 where date1 = '1955-12-13 12:43:10' +go +~~START~~ +text +Query Text: SELECT * from babel4264 where date1 = '1955-12-13 12:43:10' +Seq Scan on babel4264 + Filter: (date1 = '1955-12-13'::date) +~~END~~ + + +SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as datetime2) +go +~~START~~ +text +Query Text: SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as datetime2) +Seq Scan on babel4264 + Filter: ((date1)::datetime2 = '1955-12-13 12:43:10'::datetime2) +~~END~~ + + +SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as smalldatetime) +go +~~START~~ +text +Query Text: SELECT * from babel4264 where date1 = cast('1955-12-13 12:43:10' as smalldatetime) +Seq Scan on babel4264 + Filter: (date1 = '1955-12-13 12:43:00'::smalldatetime(0) without time zone) +~~END~~ + + +set babelfish_showplan_all off +go + +drop table babel4264 +go + +create table babel4264(dollars money) +go + +set babelfish_showplan_all on +go + +SELECT * from babel4264 where dollars = 10 +go +~~START~~ +text +Query Text: SELECT * from babel4264 where dollars = 10 +Seq Scan on babel4264 + Filter: ((dollars)::fixeddecimal = 10) +~~END~~ + + +SELECT * from babel4264 where dollars = 10.0 +go +~~START~~ +text +Query Text: SELECT * from babel4264 where dollars = 10.0 +Seq Scan on babel4264 + Filter: ((dollars)::fixeddecimal = 10.0) +~~END~~ + + +SELECT * from babel4264 where dollars = 2147483650 +go +~~START~~ +text +Query Text: SELECT * from babel4264 where dollars = 2147483650 +Seq Scan on babel4264 + Filter: ((dollars)::fixeddecimal = '2147483650'::bigint) +~~END~~ + + +SELECT * from babel4264 where dollars = '10.12' +go +~~START~~ +text +Query Text: SELECT * from babel4264 where dollars = '10.12' +Seq Scan on babel4264 + Filter: ((dollars)::fixeddecimal = '10.1200'::fixeddecimal) +~~END~~ + + +SELECT * from babel4264 where dollars = '10.123512341234' +go +~~START~~ +text +Query Text: SELECT * from babel4264 where dollars = '10.123512341234' +Seq Scan on babel4264 + Filter: ((dollars)::fixeddecimal = '10.1235'::fixeddecimal) +~~END~~ + + +SELECT * from babel4264 where dollars = cast('10' as varchar(30)) +go +~~START~~ +text +Query Text: SELECT * from babel4264 where dollars = cast('10' as varchar(30)) +Seq Scan on babel4264 + Filter: ((dollars)::fixeddecimal = '10.0000'::fixeddecimal) +~~END~~ + + +set babelfish_showplan_all off +go + +drop table babel4264 +go + +-- Not allowed +SELECT cast(cast('true' as varchar(20)) as INT) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "true")~~ + + +-- Note, negative varbinary not allowed in T-SQL +SELECT (123 + (-0x42)); +GO +~~START~~ +bigint +57 +~~END~~ + +SELECT ((-0x42) + 123); +GO +~~START~~ +bigint +57 +~~END~~ + + +SELECT (123 - 0x42); +GO +~~START~~ +int +57 +~~END~~ + +SELECT (0x42 - 123); +GO +~~START~~ +int +-57 +~~END~~ + + +-- Return type of int const and varbinary is now INT, not BIGINT. This can +-- result in overflows that didn't previously occur, but overflow matches T-SQL +SELECT (2147483640 + 0x10) +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + +SELECT (0x10 + 2147483640) +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SELECT (cast(2147483640 as bigint) + 0x10) +GO +~~START~~ +bigint +2147483656 +~~END~~ + +SELECT (0x10 + cast(2147483640 as bigint)) +GO +~~START~~ +bigint +2147483656 +~~END~~ + + +SELECT (-2147483640 - 0x10) +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + +SELECT (-0x10 - 2147483640) +GO +~~START~~ +bigint +-2147483656 +~~END~~ + + +SELECT (cast(-2147483640 as bigint) - 0x10) +GO +~~START~~ +bigint +-2147483656 +~~END~~ + +SELECT (-0x10 - cast(2147483640 as bigint)) +GO +~~START~~ +bigint +-2147483656 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4270-vu-cleanup.out b/test/JDBC/expected/BABEL-4270-vu-cleanup.out new file mode 100644 index 0000000000..f6e3dd6371 --- /dev/null +++ b/test/JDBC/expected/BABEL-4270-vu-cleanup.out @@ -0,0 +1,17 @@ +use babel_4270 +go + +drop procedure BABEL_4270_test_default_escape +go + +drop function BABEL_4270_abc +go + +drop table t +go + +use master +go + +drop database babel_4270 +go diff --git a/test/JDBC/expected/BABEL-4270-vu-prepare.out b/test/JDBC/expected/BABEL-4270-vu-prepare.out new file mode 100644 index 0000000000..41be0049d8 --- /dev/null +++ b/test/JDBC/expected/BABEL-4270-vu-prepare.out @@ -0,0 +1,83 @@ +create database babel_4270 +go +use babel_4270 +go + +create table t ( a varchar(30)); +go +insert into t values ('0'); +go +~~ROW COUNT: 1~~ + +insert into t values ('4270'); +go +~~ROW COUNT: 1~~ + +insert into t values ('0.599'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc_d_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('bbc_d_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('xbc_f_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abcdde'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc\_d\_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc\_d_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc\ad\c'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc\cd\_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc\xFEcd\_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abc\xFFcd\_'); +go +~~ROW COUNT: 1~~ + +insert into t values ('abcxFFcd\_'); +go +~~ROW COUNT: 1~~ + + +create function BABEL_4270_abc() +returns varchar(20) +as + begin + return 'abc\xFE%' + end +go + + +create procedure BABEL_4270_test_default_escape +as + begin + select * from t where a like 'abc\%' + end +go diff --git a/test/JDBC/expected/BABEL-4270-vu-verify.out b/test/JDBC/expected/BABEL-4270-vu-verify.out new file mode 100644 index 0000000000..80b6af0318 --- /dev/null +++ b/test/JDBC/expected/BABEL-4270-vu-verify.out @@ -0,0 +1,574 @@ +use babel_4270 +go + +-- check test list +select * from t +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like expression without escape clause +select * from t where a like 'abc' +go +~~START~~ +varchar +abc +~~END~~ + +select * from t where a like 'ab_' +go +~~START~~ +varchar +abc +~~END~~ + +select * from t where a like 'abc%' +go +~~START~~ +varchar +abc +abc_d_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + +select * from t where a like 'abd' +go +~~START~~ +varchar +~~END~~ + +select * from t where a like 'abd_' +go +~~START~~ +varchar +~~END~~ + +select * from t where a like 'abc%' +go +~~START~~ +varchar +abc +abc_d_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + +select * from t where a like '[a-z]bc%' +go +~~START~~ +varchar +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like expression with postgres default escape character '\' +select * from t where a like 'abc\%' +go +~~START~~ +varchar +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +~~END~~ + +select * from t where a like 'abc\_d\_' +go +~~START~~ +varchar +abc\_d\_ +abc\ad\c +abc\cd\_ +~~END~~ + + +-- not like expression with postgres default escape character '\' +select * from t where a not like 'abc\%' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abcxFFcd\_ +~~END~~ + +select * from t where a not like 'abc\_d\_' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like expression that pattern has default invalid UTF-8 character ‘\xFE’ +select * from t where a like 'abc\xFEcd\_' +go +~~START~~ +varchar +abc\xFEcd\_ +~~END~~ + +select * from t where a like 'abc\xFE%' +go +~~START~~ +varchar +abc\xFEcd\_ +~~END~~ + + +-- not like expression that pattern has default invalid UTF-8 character ‘\xFE’ +select * from t where a not like 'abc\xFEcd\_' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + +select * from t where a not like 'abc\xFE%' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like pattern from result of a select clause +select * from t where a like (select 'abc\xFE%') +go +~~START~~ +varchar +abc\xFEcd\_ +~~END~~ + +select * from t where a like (select * from t where a like (select 'abc\xFE%')) +go +~~START~~ +varchar +abc\xFEcd\_ +~~END~~ + + +-- not like pattern from result of a select clause +select * from t where a not like (select 'abc\xFE%') +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + +select * from t where a not like (select * from t where a like (select 'abc\xFE%')) +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like pattern from a variable ? +declare @f varchar(20) = 'abc%' +select * from t where a like @f +go +~~START~~ +varchar +abc +abc_d_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like pattern from a function (babelfish bug, tsql have output while bbf doesn't) +select * from t where a like BABEL_4270_abc(); +go +~~START~~ +varchar +abc\xFEcd\_ +~~END~~ + + +-- like pattern from a non-varchar pattern +select * from t where a like 0 +go +~~START~~ +varchar +0 +~~END~~ + +select * from t where a like 4270 +go +~~START~~ +varchar +4270 +~~END~~ + +select * from t where a like 4272 +go +~~START~~ +varchar +~~END~~ + +select * from t where a like 0.599 +go +~~START~~ +varchar +0.599 +~~END~~ + + +-- like expression with escape clause +select * from t where a like 'abcc_%' escape 'c' +go +~~START~~ +varchar +abc_d_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + +select * from t where a not like 'abcc_%' escape 'c' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +bbc_d_ +xbc_f_ +~~END~~ + + +-- like, escape clause with special escape clause +select * from t where a like 'abc\_%' escape '\' +go +~~START~~ +varchar +abc_d_ +~~END~~ + +select * from t where a like 'abc\\xFE_d\_' escape '\xFE' +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + +select * from t where a like 'abc_\__%' escape '_' +go +~~START~~ +varchar +abc\_d\_ +abc\_d_ +~~END~~ + + +-- not like, escape clause of special escape clause +select * from t where a not like 'abc\_%' escape '\' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + +select * from t where a not like 'abc\\xFE_d\_' escape '\xFE' +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + +select * from t where a not like 'abc_\__%' escape '_' +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like, escape character is from result of a select clause +select * from t where a like 'abc\_%' escape (select '\') +go +~~START~~ +varchar +abc_d_ +~~END~~ + + +select * from t where a not like 'abc\\xFE_d\_' escape ( select'\xFE') +go +~~START~~ +varchar +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + + +select * from t where a not like 'abc_\__%' escape (select '_') +go +~~START~~ +varchar +0 +4270 +0.599 +abc +abc_d_ +bbc_d_ +xbc_f_ +abcdde +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +-- like, escape character is from a variable +declare @f varchar(20) = '\xFE' +select * from t where a like 'abc\\xFE_d\_' escape @f +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + + +declare @f varchar(20) = '\' +select * from t where a like 'abc\_%' escape @f +go +~~START~~ +varchar +abc_d_ +~~END~~ + + +-- like pattern and escape character both come from a variable +declare @f varchar(20) = '\' +declare @d varchar(20) = 'abc\_%' +select * from t where a like @d escape @f +go +~~START~~ +varchar +abc_d_ +~~END~~ + + +declare @f varchar(20) = '\xFE' +declare @d varchar(20) = 'abc\\xFE_d\_' +select * from t where a like @d escape @f +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + + +-- not like pattern and escape character both come from a variable +declare @f varchar(20) = '\' +declare @d varchar(20) = 'abc\_%' +select * from t where a not like @d escape @f +go +~~START~~ +varchar +0 +4270 +0.599 +abc +bbc_d_ +xbc_f_ +abcdde +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +abcxFFcd\_ +~~END~~ + + +declare @f varchar(20) = '\xFE' +declare @d varchar(20) = 'abc\\xFE_d\_' +select * from t where a not like @d escape @f +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + + +-- like, escape character is from a non-varchar value +select * from t where a like 'abc0\0_%' escape 0 +go +~~START~~ +varchar +abc\_d\_ +abc\_d_ +~~END~~ + + +-- like, escape character is from a non-varchar value +select * from t where a like 'abc0\0_%' escape 0.5 +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + + +-- like expression with default escape '\' in a procedure +exec BABEL_4270_test_default_escape +go +~~START~~ +varchar +abc\_d\_ +abc\_d_ +abc\ad\c +abc\cd\_ +abc\xFEcd\_ +abc\xFFcd\_ +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4271-vu-cleanup.out b/test/JDBC/expected/BABEL-4271-vu-cleanup.out new file mode 100644 index 0000000000..f71d676733 --- /dev/null +++ b/test/JDBC/expected/BABEL-4271-vu-cleanup.out @@ -0,0 +1,3 @@ +-- Test to check like escape null and like escape '' +drop table babel_4271_vu_prepare_t1; +go diff --git a/test/JDBC/expected/BABEL-4271-vu-prepare.out b/test/JDBC/expected/BABEL-4271-vu-prepare.out new file mode 100644 index 0000000000..c0d97b4053 --- /dev/null +++ b/test/JDBC/expected/BABEL-4271-vu-prepare.out @@ -0,0 +1,26 @@ +-- Test to check like escape null and like escape '' +create table babel_4271_vu_prepare_t1(a varchar(30), b varchar(30)); +go + +insert into babel_4271_vu_prepare_t1 values ('cbc','[c-a]bc'); +insert into babel_4271_vu_prepare_t1 values ('cbc','[a-c]bc'); +insert into babel_4271_vu_prepare_t1 values ('abc','abc'); +insert into babel_4271_vu_prepare_t1 values ('cbc','def'); +insert into babel_4271_vu_prepare_t1 values (' abc','abc') +insert into babel_4271_vu_prepare_t1 values ('abc','def') +insert into babel_4271_vu_prepare_t1 values ('','') +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/BABEL-4271-vu-verify.out b/test/JDBC/expected/BABEL-4271-vu-verify.out new file mode 100644 index 0000000000..5d7dbfb63b --- /dev/null +++ b/test/JDBC/expected/BABEL-4271-vu-verify.out @@ -0,0 +1,183 @@ +-- Test to check ESCAPE null case (ESCAPE null means no ESCAPE char used) +select 1 where 'ABCD' LIKE 'AB[C]D' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select 1 where 'cbc' LIKE '[c-a]bc' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select 1 where 'abc' LIKE '[0-a]bc' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select 1 where 'abc' LIKE '[abc]bc' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select 1 where 'abc' LIKE '[a-c]bc' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select 1 where 'bbc' LIKE '[a-c]bc' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select a, b from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE babel_4271_vu_prepare_t1.b ESCAPE ''; +go +~~START~~ +varchar#!#varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +SELECT a, '' from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE '' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +SELECT a, 'abc' from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE '' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +SELECT '', '' from babel_4271_vu_prepare_t1 where '' LIKE babel_4271_vu_prepare_t1.b ESCAPE ''; +go +~~START~~ +varchar#!#varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +SELECT 'xy', b from babel_4271_vu_prepare_t1 where 'cbc' LIKE babel_4271_vu_prepare_t1.a ESCAPE ''; +go +~~START~~ +varchar#!#varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +SELECT a, b from babel_4271_vu_prepare_t1 where '' LIKE '' ESCAPE ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +-- Test to check ESCAPE null case (ESCAPE null means no ESCAPE char used) +select 1 where 'ABCD' LIKE 'AB[C]D' ESCAPE null; +go +~~START~~ +int +1 +~~END~~ + +select 1 where 'cbc' LIKE '[c-a]bc' ESCAPE null; +go +~~START~~ +int +~~END~~ + +select 1 where 'abc' LIKE '[0-a]bc' ESCAPE null; +go +~~START~~ +int +1 +~~END~~ + +select 1 where 'abc' LIKE '[abc]bc' ESCAPE null; +go +~~START~~ +int +1 +~~END~~ + +select 1 where 'abc' LIKE '[a-c]bc' ESCAPE null; +go +~~START~~ +int +1 +~~END~~ + +select 1 where 'bbc' LIKE '[a-c]bc' ESCAPE null; +go +~~START~~ +int +1 +~~END~~ + +select a, b from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE babel_4271_vu_prepare_t1.b ESCAPE null; +go +~~START~~ +varchar#!#varchar +cbc#!#[a-c]bc +abc#!#abc +#!# +~~END~~ + +SELECT a, 'abc' from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE 'abc' ESCAPE null; +go +~~START~~ +varchar#!#varchar +abc#!#abc +abc#!#abc +~~END~~ + +SELECT a, '' from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE babel_4271_vu_prepare_t1.b ESCAPE null; +go +~~START~~ +varchar#!#varchar +cbc#!# +abc#!# +#!# +~~END~~ + +SELECT a, '' from babel_4271_vu_prepare_t1 where babel_4271_vu_prepare_t1.a LIKE '' ESCAPE null; +go +~~START~~ +varchar#!#varchar +#!# +~~END~~ + +SELECT 'xy', b from babel_4271_vu_prepare_t1 where 'cbc' LIKE babel_4271_vu_prepare_t1.a ESCAPE null; +go +~~START~~ +varchar#!#varchar +xy#!#[c-a]bc +xy#!#[a-c]bc +xy#!#def +~~END~~ + +SELECT '', '' from babel_4271_vu_prepare_t1 where '' LIKE babel_4271_vu_prepare_t1.b ESCAPE null; +go +~~START~~ +varchar#!#varchar +#!# +~~END~~ + +SELECT a, b from babel_4271_vu_prepare_t1 where '' LIKE '' ESCAPE null; +go +~~START~~ +varchar#!#varchar +cbc#!#[c-a]bc +cbc#!#[a-c]bc +abc#!#abc +cbc#!#def + abc#!#abc +abc#!#def +#!# +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4279-vu-cleanup.out b/test/JDBC/expected/BABEL-4279-vu-cleanup.out new file mode 100644 index 0000000000..8226350864 --- /dev/null +++ b/test/JDBC/expected/BABEL-4279-vu-cleanup.out @@ -0,0 +1,60 @@ +-- tsql +DROP VIEW test_babel_4279_v1; +GO + +DROP VIEW test_babel_4279_v2; +GO + +DROP VIEW test_babel_4279_v3; +GO + +DROP TABLE test_babel_4279_t1; +GO + +USE [test_babel_4279_d.1]; +GO + +DROP VIEW test_babel_4279_sv1; +GO + +DROP TABLE test_babel_4279_s1.test_babel_4279_st1; +GO + +DROP SCHEMA test_babel_4279_s1; +GO + +USE MASTER; +GO + +DROP DATABASE [test_babel_4279_d.1]; +GO + +DROP VIEW test_babel_4279_v4; +GO + +DROP VIEW test_babel_4279_v5; +GO + +DROP TABLE test_babel_4279_t2; +GO + +DROP VIEW test_babel_4279_v6; +GO + +DROP TABLE "tngdf'".[sc,sdg"fdsngjds']; +GO + +DROP SCHEMA "tngdf'"; +GO + +DROP VIEW test_babel_4279_v7; +GO + +DROP TABLE test_babel_4279_t3; +GO + +DROP VIEW test_babel_4279_v8; +GO + +DROP TABLE test_babel_4279_t4; +GO diff --git a/test/JDBC/expected/BABEL-4279-vu-prepare.out b/test/JDBC/expected/BABEL-4279-vu-prepare.out new file mode 100644 index 0000000000..940c5b89ed --- /dev/null +++ b/test/JDBC/expected/BABEL-4279-vu-prepare.out @@ -0,0 +1,60 @@ +-- tsql +CREATE TABLE test_babel_4279_t1([ABC.nfds] INT, [DEf.j] INT); +GO + +CREATE VIEW test_babel_4279_v1 AS SELECT test_babel_4279_t1.[ABC.nfds] from test_babel_4279_t1; +GO + +CREATE VIEW test_babel_4279_v2 AS SELECT [test_babel_4279_t1].[ABC.nfds] ,test_babel_4279_t1.[DEf.j] from test_babel_4279_t1; +GO + +CREATE DATABASE [test_babel_4279_d.1]; +GO + +USE [test_babel_4279_d.1]; +GO + +CREATE SCHEMA test_babel_4279_s1; +GO + +CREATE TABLE test_babel_4279_s1.test_babel_4279_st1([ABC.nfds] INT, [DEf.j] INT); +GO + +CREATE VIEW test_babel_4279_sv1 AS SELECT [test_babel_4279_s1].[test_babel_4279_st1].[ABC.nfds] from test_babel_4279_s1.test_babel_4279_st1; +GO + +USE MASTER +GO + +CREATE VIEW test_babel_4279_v3 AS SELECT [test_babel_4279_d.1].[test_babel_4279_s1].[test_babel_4279_st1].[ABC.nfds] from [test_babel_4279_d.1].[test_babel_4279_s1].[test_babel_4279_st1]; +GO + +CREATE TABLE test_babel_4279_t2(您您对您对您对您对您对您对您对您对您对您您您 INT, 对您对您对您对您对您对您对您 INT); +GO + +CREATE VIEW test_babel_4279_v4 AS SELECT test_babel_4279_t2.[您您对您对您对您对您对您对您对您对您对您您您] from test_babel_4279_t2; +GO + +CREATE VIEW test_babel_4279_v5 AS SELECT ãã‚.[您您对您对您对您对您对您对您对您对您对您您您] from test_babel_4279_t2 AS ãã‚; +GO + +CREATE SCHEMA "tngdf'"; +GO + +CREATE TABLE "tngdf'".[sc,sdg"fdsngjds']("AB[C" INT); +GO + +CREATE VIEW test_babel_4279_v6 AS SELECT "tngdf'".[sc,sdg"fdsngjds']."AB[C" from "tngdf'".[sc,sdg"fdsngjds']; +GO + +CREATE TABLE test_babel_4279_t3(ABCD INT); +GO + +CREATE VIEW test_babel_4279_v7 AS SELECT test_babel_4279_t3.ABCD FROM test_babel_4279_t3; +GO + +CREATE TABLE test_babel_4279_t4([ãã‚'"] INT); +GO + +CREATE VIEW test_babel_4279_v8 AS SELECT test_babel_4279_t4.[ãã‚'"] FROM test_babel_4279_t4; +GO diff --git a/test/JDBC/expected/BABEL-4279-vu-verify.out b/test/JDBC/expected/BABEL-4279-vu-verify.out new file mode 100644 index 0000000000..46b9b8aae7 --- /dev/null +++ b/test/JDBC/expected/BABEL-4279-vu-verify.out @@ -0,0 +1,72 @@ +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v1'; +GO +~~START~~ +text + SELECT test_babel_4279_t1."abc.nfds" AS "ABC.nfds" FROM master_dbo.test_babel_4279_t1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v2'; +GO +~~START~~ +text + SELECT test_babel_4279_t1."abc.nfds" AS "ABC.nfds", test_babel_4279_t1."def.j" AS "DEf.j" FROM master_dbo.test_babel_4279_t1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_sv1'; +GO +~~START~~ +text + SELECT test_babel_4279_st1."abc.nfds" AS "ABC.nfds" FROM "test_babel_4279_d.1_test_babel_4279_s1".test_babel_4279_st1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v3'; +GO +~~START~~ +text + SELECT test_babel_4279_st1."abc.nfds" AS "ABC.nfds" FROM "test_babel_4279_d.1_test_babel_4279_s1".test_babel_4279_st1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v4'; +GO +~~START~~ +text + SELECT test_babel_4279_t2."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de" FROM master_dbo.test_babel_4279_t2; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v5'; +GO +~~START~~ +text + SELECT "ãã‚"."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de" FROM master_dbo.test_babel_4279_t2 "ãã‚"; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v6'; +GO +~~START~~ +text + SELECT "sc,sdg""fdsngjds'"."ab[c" AS "AB[C" FROM "master_tngdf'"."sc,sdg""fdsngjds'"; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v7'; +GO +~~START~~ +text + SELECT test_babel_4279_t3.abcd AS "ABCD" FROM master_dbo.test_babel_4279_t3; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v8'; +GO +~~START~~ +text + SELECT test_babel_4279_t4."ãã‚'""" FROM master_dbo.test_babel_4279_t4; +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4279.out b/test/JDBC/expected/BABEL-4279.out new file mode 100644 index 0000000000..1f59a4f4f5 --- /dev/null +++ b/test/JDBC/expected/BABEL-4279.out @@ -0,0 +1,237 @@ +-- tsql +CREATE TABLE test_babel_4279_t1([ABC.nfds] INT, [DEf.j] INT); +GO + +CREATE VIEW test_babel_4279_v1 AS SELECT test_babel_4279_t1.[ABC.nfds] from test_babel_4279_t1; +GO + +CREATE VIEW test_babel_4279_v2 AS SELECT [test_babel_4279_t1].[ABC.nfds] ,test_babel_4279_t1.[DEf.j] from test_babel_4279_t1; +GO + +CREATE DATABASE ["test_babel_4279_d.1"]; +GO + +USE ["test_babel_4279_d.1"]; +GO + +CREATE SCHEMA test_babel_4279_s1; +GO + +CREATE TABLE test_babel_4279_s1.test_babel_4279_st1([ABC.nfds] INT, [DEf.j] INT); +GO + +CREATE VIEW test_babel_4279_sv1 AS SELECT [test_babel_4279_s1].[test_babel_4279_st1].[ABC.nfds] from test_babel_4279_s1.test_babel_4279_st1; +GO + +USE MASTER +GO + +CREATE VIEW test_babel_4279_v3 AS SELECT ["test_babel_4279_d.1"].[test_babel_4279_s1].[test_babel_4279_st1].[ABC.nfds] from ["test_babel_4279_d.1"].[test_babel_4279_s1].[test_babel_4279_st1]; +GO + +CREATE TABLE test_babel_4279_t2(您您对您对您对您对您对您对您对您对您对您您您 INT, 对您对您对您对您对您对您对您 INT); +GO + +CREATE VIEW test_babel_4279_v4 AS SELECT test_babel_4279_t2.[您您对您对您对您对您对您对您对您对您对您您您] from test_babel_4279_t2; +GO + +CREATE VIEW test_babel_4279_v5 AS SELECT ãã‚.[您您对您对您对您对您对您对您对您对您对您您您] from test_babel_4279_t2 AS ãã‚; +GO + +CREATE SCHEMA "tngdf'"; +GO + +CREATE TABLE "tngdf'".[sc,sdg"fdsngjds']("AB[C" INT); +GO + +CREATE VIEW test_babel_4279_v6 AS SELECT "tngdf'".[sc,sdg"fdsngjds']."AB[C" from "tngdf'".[sc,sdg"fdsngjds']; +GO + +CREATE TABLE test_babel_4279_t3(ABCD INT); +GO + +CREATE VIEW test_babel_4279_v7 AS SELECT test_babel_4279_t3.ABCD FROM test_babel_4279_t3; +GO + +CREATE TABLE test_babel_4279_t4([ãã‚'"] INT); +GO + +CREATE VIEW test_babel_4279_v8 AS SELECT test_babel_4279_t4.[ãã‚'"] FROM test_babel_4279_t4; +GO + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v1'; +GO +~~START~~ +text + SELECT test_babel_4279_t1."abc.nfds" AS "ABC.nfds" FROM master_dbo.test_babel_4279_t1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v2'; +GO +~~START~~ +text + SELECT test_babel_4279_t1."abc.nfds" AS "ABC.nfds", test_babel_4279_t1."def.j" AS "DEf.j" FROM master_dbo.test_babel_4279_t1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_sv1'; +GO +~~START~~ +text + SELECT test_babel_4279_st1."abc.nfds" AS "ABC.nfds" FROM test_babel_4279_s1.test_babel_4279_st1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v3'; +GO +~~START~~ +text + SELECT test_babel_4279_st1."abc.nfds" AS "ABC.nfds" FROM test_babel_4279_s1.test_babel_4279_st1; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v4'; +GO +~~START~~ +text + SELECT test_babel_4279_t2."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de" FROM master_dbo.test_babel_4279_t2; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v5'; +GO +~~START~~ +text + SELECT "ãã‚"."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de" FROM master_dbo.test_babel_4279_t2 "ãã‚"; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v6'; +GO +~~START~~ +text + SELECT "sc,sdg""fdsngjds'"."ab[c" AS "AB[C" FROM "master_tngdf'"."sc,sdg""fdsngjds'"; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v7'; +GO +~~START~~ +text + SELECT test_babel_4279_t3.abcd AS "ABCD" FROM master_dbo.test_babel_4279_t3; +~~END~~ + + +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'test_babel_4279_v8'; +GO +~~START~~ +text + SELECT test_babel_4279_t4."ãã‚'""" FROM master_dbo.test_babel_4279_t4; +~~END~~ + + +-- tsql +DROP VIEW test_babel_4279_v1; +GO + +DROP VIEW test_babel_4279_v2; +GO + +DROP VIEW test_babel_4279_v3; +GO + +DROP TABLE test_babel_4279_t1; +GO + +USE ["test_babel_4279_d.1"]; +GO + +DROP VIEW test_babel_4279_sv1; +GO + +DROP TABLE test_babel_4279_s1.test_babel_4279_st1; +GO + +DROP SCHEMA test_babel_4279_s1; +GO + +USE MASTER; +GO + +DROP DATABASE ["test_babel_4279_d.1"]; +GO + +DROP VIEW test_babel_4279_v4; +GO + +DROP VIEW test_babel_4279_v5; +GO + +DROP TABLE test_babel_4279_t2; +GO + +DROP VIEW test_babel_4279_v6; +GO + +DROP TABLE "tngdf'".[sc,sdg"fdsngjds']; +GO + +DROP SCHEMA "tngdf'"; +GO + +DROP VIEW test_babel_4279_v7; +GO + +DROP TABLE test_babel_4279_t3; +GO + +DROP VIEW test_babel_4279_v8; +GO + +DROP TABLE test_babel_4279_t4; +GO + +CREATE TABLE t2(c int) +GO + +CREATE TABLE t1(c int) +GO + +-- should not crash when column followed by '\n'|'\t' etc. +CREATE VIEW v +AS +SELECT t1.c +FROM dbo.t2 INNER JOIN t1 +ON t2.c = t1.c +GO + +DROP VIEW v +GO + +DROP TABLE t2 +GO + +DROP TABLE t1 +GO + +CREATE TABLE t3(RecordEntryId bigint NOT NULL) +GO + +CREATE FUNCTION tvf_t3(@UserId BIGINT) +RETURNS TABLE +AS +RETURN +( +select rp.RecordEntryId +from dbo.t3 rp +) +GO + +DROP FUNCTION tvf_t3 +GO + +DROP TABLE t3 +GO + diff --git a/test/JDBC/expected/BABEL-4281.out b/test/JDBC/expected/BABEL-4281.out new file mode 100644 index 0000000000..d3a6d420a0 --- /dev/null +++ b/test/JDBC/expected/BABEL-4281.out @@ -0,0 +1,116 @@ +BEGIN TRAN BABEL4281_T1; +GO + +CREATE TABLE t_babel4281 (a int, b int); +GO + +-- The third parameter is true to set config back to default after transaction is committed +select set_config('parallel_setup_cost', 0, true); +select set_config('parallel_tuple_cost', 0, true); +select set_config('min_parallel_table_scan_size', 0, true); +GO +~~START~~ +text +0 +~~END~~ + +~~START~~ +text +0 +~~END~~ + +~~START~~ +text +0 +~~END~~ + + + +-- show explicitly this is a parallel query plan +select set_config('babelfishpg_tsql.explain_timing', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.explain_summary', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.explain_costs', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL ON +GO + +select a, count(*) from t_babel4281 group by a order by 2; -- should not crash +GO +~~START~~ +text +Query Text: select a, count(*) from t_babel4281 group by a order by 2 +Sort + Sort Key: (count(*)) NULLS FIRST + -> Finalize HashAggregate + Group Key: a + -> Gather + Workers Planned: 2 + -> Partial HashAggregate + Group Key: a + -> Parallel Seq Scan on t_babel4281 +~~END~~ + + +-- set configurations back +SET BABELFISH_SHOWPLAN_ALL OFF +GO + +-- Verify Output +select a, count(*) from t_babel4281 group by a order by 2; -- should not crash +GO +~~START~~ +int#!#int +~~END~~ + + +select set_config('babelfishpg_tsql.explain_timing', 'on', false); +GO +~~START~~ +text +on +~~END~~ + + +select set_config('babelfishpg_tsql.explain_summary', 'on', false); +GO +~~START~~ +text +on +~~END~~ + + +select set_config('babelfishpg_tsql.explain_costs', 'on', false); +GO +~~START~~ +text +on +~~END~~ + + +-- Commiting sets parallel_setup_cost, parallel_tuple_cost, min_parallel_table_scan_size back to default +COMMIT TRAN BABEL4281_T1; +GO + + +DROP TABLE t_babel4281; +GO diff --git a/test/JDBC/expected/BABEL-4294-vu-cleanup.out b/test/JDBC/expected/BABEL-4294-vu-cleanup.out new file mode 100644 index 0000000000..27908b4de2 --- /dev/null +++ b/test/JDBC/expected/BABEL-4294-vu-cleanup.out @@ -0,0 +1,9 @@ + +-- Test to check if initialisation of Parallel Worker crash when babelfishpg_tsql.enable_pg_hint is set +drop table babel_4294_t1; +drop table babel_4294_t2; +drop table babel_4294_t3; +go + +drop table babel_4294_t4; +go diff --git a/test/JDBC/expected/BABEL-4294-vu-prepare.out b/test/JDBC/expected/BABEL-4294-vu-prepare.out new file mode 100644 index 0000000000..de31202caf --- /dev/null +++ b/test/JDBC/expected/BABEL-4294-vu-prepare.out @@ -0,0 +1,20 @@ + +-- Test to check if initialisation of Parallel Worker crash when babelfishpg_tsql.enable_pg_hint is set +create table babel_4294_t1(id INT, val int); +create table babel_4294_t2(babel_4294_t1_id INT, val int); +create table babel_4294_t3(babel_4294_t1_id INT, val int); +go + +insert into babel_4294_t1 values (1, 10), (2, 20), (3, 30); +insert into babel_4294_t2 values (1, 11), (2, 12), (3, 13); +insert into babel_4294_t3 values (1, 99), (2, 77), (3, 55); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + + +create table babel_4294_t4(id INT, val int); +go diff --git a/test/JDBC/expected/BABEL-4294-vu-verify.out b/test/JDBC/expected/BABEL-4294-vu-verify.out new file mode 100644 index 0000000000..26eb15be04 --- /dev/null +++ b/test/JDBC/expected/BABEL-4294-vu-verify.out @@ -0,0 +1,56 @@ + +-- Test to check if initialisation of Parallel Worker crash when babelfishpg_tsql.enable_pg_hint is set +/* + * Set the enable_pg_hint, try to create parallel worker + */ +exec sp_babelfish_configure 'enable_pg_hint', 'on', 'server' +go + +select COUNT( babel_4294_t3.val), babel_4294_t2.val from babel_4294_t1 +inner join babel_4294_t2 on babel_4294_t1.id = babel_4294_t2.babel_4294_t1_id +inner join babel_4294_t3 on babel_4294_t1.id = babel_4294_t3.babel_4294_t1_id +GROUP BY babel_4294_t2.val +UNION ALL +select COUNT( babel_4294_t3.val), babel_4294_t2.val from babel_4294_t1 +inner join babel_4294_t2 on babel_4294_t1.id = babel_4294_t2.babel_4294_t1_id +inner join babel_4294_t3 on babel_4294_t1.id = babel_4294_t3.babel_4294_t1_id +GROUP BY babel_4294_t2.val +go +~~START~~ +int#!#int +1#!#11 +1#!#13 +1#!#12 +1#!#11 +1#!#13 +1#!#12 +~~END~~ + + +-- Used force parallel mode to create a parallel worker +select set_config('force_parallel_mode', '1', false) +go +~~START~~ +text +on +~~END~~ + + +-- to check if parallel worker generated for following query, will crash or not +select * from babel_4294_t4 +go +~~START~~ +int#!#int +~~END~~ + + +select set_config('force_parallel_mode', '0', false) +go +~~START~~ +text +off +~~END~~ + + +exec sp_babelfish_configure 'enable_pg_hint', 'off', 'server' +go diff --git a/test/JDBC/expected/BABEL-4327.out b/test/JDBC/expected/BABEL-4327.out new file mode 100644 index 0000000000..10d77faa80 --- /dev/null +++ b/test/JDBC/expected/BABEL-4327.out @@ -0,0 +1,84 @@ +CREATE TABLE [dbo].[test_babel_4327_table]( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [my_varchar_data] [varchar](20) NULL, + [my_computed_column] AS isnull([my_varchar_data],[id])); +GO + +-- should be sys.varchar +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + name = 'my_computed_column' and + object_id = + ( + select object_id from sys.tables where name = 'test_babel_4327_table' + ) +); +GO +~~START~~ +text +varchar +~~END~~ + + +INSERT INTO [dbo].[test_babel_4327_table]([my_varchar_data])VALUES ('1'); +INSERT INTO [dbo].[test_babel_4327_table]([my_varchar_data])VALUES ('HELLO'); +INSERT INTO [dbo].[test_babel_4327_table]([my_varchar_data])VALUES (NULL); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_babel_4327_table]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +#!#Unassigned#!#HELLO#!#Unassigned#!# +#!#Unassigned#!#Unassigned#!#Unassigned#!# +~~END~~ + + +select * from [dbo].[test_babel_4327_table] where ISNULL([my_varchar_data], [id]) = 'HELLO'; +GO +~~START~~ +bigint#!#varchar#!#varchar +2#!#HELLO#!#HELLO +~~END~~ + + +select * from [dbo].[test_babel_4327_table] where [my_computed_column] = 'HELLO'; +GO +~~START~~ +bigint#!#varchar#!#varchar +2#!#HELLO#!#HELLO +~~END~~ + + +select * from [dbo].[test_babel_4327_table] where ISNULL([my_varchar_data], [id]) = 'HeLLO'; +GO +~~START~~ +bigint#!#varchar#!#varchar +2#!#HELLO#!#HELLO +~~END~~ + + +select * from [dbo].[test_babel_4327_table] where [my_computed_column] = 'HeLLO'; +GO +~~START~~ +bigint#!#varchar#!#varchar +2#!#HELLO#!#HELLO +~~END~~ + + +DROP TABLE [dbo].[test_babel_4327_table]; +GO diff --git a/test/JDBC/expected/BABEL-4342.out b/test/JDBC/expected/BABEL-4342.out new file mode 100644 index 0000000000..038bb772dc --- /dev/null +++ b/test/JDBC/expected/BABEL-4342.out @@ -0,0 +1,58 @@ +-- psql +CREATE PROCEDURE sys.babel_4342_proc1() +LANGUAGE 'pltsql' AS $$ +BEGIN +DECLARE @objtype sys.VARCHAR(2) +SELECT @objtype = type COLLATE DATABASE_DEFAULT FROM sys.sysobjects WHERE id = 1 +END +$$; +GO + +CREATE OR REPLACE PROCEDURE sys.babel_4342_proc2() +LANGUAGE 'pltsql' +AS $$ +BEGIN +DECLARE @objtype sys.VARCHAR(2) +SELECT @objtype = type FROM sys.sysobjects WHERE id = 1 +END +$$; +GO + +CREATE OR REPLACE PROCEDURE sys.babel_4342_proc3() +LANGUAGE 'pltsql' +AS $$ +BEGIN +DECLARE @objtype VARCHAR(2) +SELECT @objtype = type FROM sys.sysobjects WHERE id = 1 +END +$$; +GO + +CALL sys.babel_4342_proc1(); +GO + +CALL sys.babel_4342_proc2(); +GO + +CALL sys.babel_4342_proc3(); +GO + +-- tsql +EXEC sys.babel_4342_proc1; +GO + +EXEC sys.babel_4342_proc2; +GO + +EXEC sys.babel_4342_proc3; +GO + +-- psql +DROP PROCEDURE sys.babel_4342_proc1; +GO + +DROP PROCEDURE sys.babel_4342_proc2; +GO + +DROP PROCEDURE sys.babel_4342_proc3; +GO diff --git a/test/JDBC/expected/BABEL-4384-vu-cleanup.out b/test/JDBC/expected/BABEL-4384-vu-cleanup.out new file mode 100644 index 0000000000..94a166ddae --- /dev/null +++ b/test/JDBC/expected/BABEL-4384-vu-cleanup.out @@ -0,0 +1,30 @@ +-- tsql +DROP VIEW babel_4384_v1; +GO + +DROP VIEW babel_4384_v2; +GO + +DROP VIEW babel_4384_v3; +GO + +DROP VIEW babel_4384_v4; +GO + +DROP VIEW babel_4384_v5; +GO + +DROP VIEW babel_4384_v6; +GO + +DROP VIEW babel_4384_v7; +GO + +DROP table babel_4384_t1; +GO + +DROP table babel_4384_t2; +GO + +DROP table babel_4384_t3; +GO diff --git a/test/JDBC/expected/BABEL-4384-vu-prepare.out b/test/JDBC/expected/BABEL-4384-vu-prepare.out new file mode 100644 index 0000000000..468686a4cf --- /dev/null +++ b/test/JDBC/expected/BABEL-4384-vu-prepare.out @@ -0,0 +1,30 @@ +-- tsql +CREATE TABLE babel_4384_t1(ABC INT, [DE.f] INT); +GO + +CREATE VIEW babel_4384_v1 AS SELECT (ABC) FROM babel_4384_t1; +GO + +CREATE VIEW babel_4384_v2 AS SELECT (((ABC))) FROM babel_4384_t1; +GO + +CREATE VIEW babel_4384_v3 AS SELECT ( ( (ABC))) FROM babel_4384_t1; +GO + +CREATE VIEW babel_4384_v4 AS SELECT (( (ABC)) ) FROM babel_4384_t1; +GO + +CREATE VIEW babel_4384_v5 AS SELECT ( ( ([DE.f]))) FROM babel_4384_t1; +GO + +CREATE TABLE babel_4384_t2(您对 INT); +GO + +CREATE VIEW babel_4384_v6 AS SELECT ( ( (您对))) FROM babel_4384_t2; +GO + +CREATE TABLE babel_4384_t3(您您对您对您对您对您对您对您对您对您对您您您 INT); +GO + +CREATE VIEW babel_4384_v7 AS SELECT ( ( (您您对您对您对您对您对您对您对您对您对您您您))) FROM babel_4384_t3; +GO diff --git a/test/JDBC/expected/BABEL-4384-vu-verify.out b/test/JDBC/expected/BABEL-4384-vu-verify.out new file mode 100644 index 0000000000..409afcb2d6 --- /dev/null +++ b/test/JDBC/expected/BABEL-4384-vu-verify.out @@ -0,0 +1,62 @@ +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v1'; +GO +~~START~~ +text + SELECT babel_4384_t1.abc AS "ABC" FROM master_dbo.babel_4384_t1; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v2'; +GO +~~START~~ +text + SELECT babel_4384_t1.abc AS "ABC" FROM master_dbo.babel_4384_t1; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v3'; +GO +~~START~~ +text + SELECT babel_4384_t1.abc AS "ABC" FROM master_dbo.babel_4384_t1; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v4'; +GO +~~START~~ +text + SELECT babel_4384_t1.abc AS "ABC" FROM master_dbo.babel_4384_t1; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v5'; +GO +~~START~~ +text + SELECT babel_4384_t1."de.f" AS "DE.f" FROM master_dbo.babel_4384_t1; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v6'; +GO +~~START~~ +text + SELECT babel_4384_t2."您对" FROM master_dbo.babel_4384_t2; +~~END~~ + + +-- psql +SELECT pg_catalog.pg_get_viewdef(oid, true) FROM pg_class WHERE relname = 'babel_4384_v7'; +GO +~~START~~ +text + SELECT babel_4384_t3."您您对您对您对您对您d60211ff7d947ff09db87babbf0cb9de" FROM master_dbo.babel_4384_t3; +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4406.out b/test/JDBC/expected/BABEL-4406.out new file mode 100644 index 0000000000..ccc96ab38a --- /dev/null +++ b/test/JDBC/expected/BABEL-4406.out @@ -0,0 +1,32 @@ +-- MASTER is a T-SQL keyword in ANTLR however according to T-SQL it isn't +-- When doing T-SQL parsing it will not throw syntax error and rewrite will +-- happen as expected. We will throw server does not exist error +SELECT COLUMN_NAME from master.[JDG_Refund_Requests].information_schema.columns where [TABLE_NAME] = 'vw_All_Requests' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server "master" does not exist)~~ + + +SELECT * FROM OPENQUERY(master, 'select * from a.b.c.d') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server "master" does not exist)~~ + + +-- MERGE is a T-SQL keyword and in ANTLR as well +-- So we will throw syntax error in T-SQL parsing itself +SELECT COLUMN_NAME from merge.[JDG_Refund_Requests].information_schema.columns where [TABLE_NAME] = 'vw_All_Requests' +GO +~~ERROR (Code: 10733)~~ + +~~ERROR (Message: syntax error near 'merge' at line 3 and character position 24)~~ + + +SELECT * FROM OPENQUERY(merge, 'select * from a.b.c.d') +GO +~~ERROR (Code: 10733)~~ + +~~ERROR (Message: syntax error near 'merge' at line 1 and character position 24)~~ + diff --git a/test/JDBC/expected/BABEL-4410-vu-cleanup.out b/test/JDBC/expected/BABEL-4410-vu-cleanup.out new file mode 100644 index 0000000000..e6db5e0189 --- /dev/null +++ b/test/JDBC/expected/BABEL-4410-vu-cleanup.out @@ -0,0 +1,12 @@ +-- tsql +USE babel_4410_db +GO + +DROP TABLE [dbo].[babel_4410_My_Table] +GO + +USE master +GO + +DROP DATABASE babel_4410_db +GO diff --git a/test/JDBC/expected/BABEL-4410-vu-prepare.out b/test/JDBC/expected/BABEL-4410-vu-prepare.out new file mode 100644 index 0000000000..a58abd504a --- /dev/null +++ b/test/JDBC/expected/BABEL-4410-vu-prepare.out @@ -0,0 +1,12 @@ +-- tsql +CREATE DATABASE babel_4410_db +GO + +USE babel_4410_db +GO + +CREATE TABLE [dbo].[babel_4410_My_Table]( + [My_ID] [VARCHAR](3) NOT NULL, + [My_Column] [VARCHAR](250) NOT NULL +) +GO diff --git a/test/JDBC/expected/BABEL-4410-vu-verify.out b/test/JDBC/expected/BABEL-4410-vu-verify.out new file mode 100644 index 0000000000..d8c74cd32c --- /dev/null +++ b/test/JDBC/expected/BABEL-4410-vu-verify.out @@ -0,0 +1,85 @@ +-- psql +SELECT table_schema, table_name, column_name, udt_schema, udt_name, collation_schema, collation_name +FROM information_schema.columns +WHERE table_schema='information_schema_tsql' + AND table_name='tables' + AND column_name='TABLE_TYPE'; +GO +~~START~~ +name#!#name#!#name#!#name#!#name#!#name#!#name +information_schema_tsql#!#tables#!#TABLE_TYPE#!#sys#!#varchar#!#sys#!#bbf_unicode_cp1_ci_as +~~END~~ + + +-- tsql +USE babel_4410_db +GO + +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = DB_NAME() AND TABLE_NAME = 'babel_4410_My_Table' +GO +~~START~~ +nvarchar#!#nvarchar#!#varchar#!#varchar +babel_4410_db#!#dbo#!#babel_4410_My_Table#!#BASE TABLE +~~END~~ + + +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'base table' +GO +~~START~~ +nvarchar#!#nvarchar#!#varchar#!#varchar +babel_4410_db#!#dbo#!#babel_4410_My_Table#!#BASE TABLE +~~END~~ + + +SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' +GO +~~START~~ +nvarchar#!#nvarchar#!#varchar#!#varchar +babel_4410_db#!#dbo#!#babel_4410_My_Table#!#BASE TABLE +~~END~~ + + +IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'babel_4410_My_Table')) +BEGIN + SELECT 'TABLE EXISTS - THIS IS CORRECT' +END +ELSE +BEGIN + SELECT 'TABLE NOT EXISTS - THIS IS WRONG, BECAUSE IT DOES EXIST' +END +GO +~~START~~ +varchar +TABLE EXISTS - THIS IS CORRECT +~~END~~ + + +IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'babel_4410_My_Table')) +BEGIN + SELECT 'TABLE NOT EXISTS - THIS IS WRONG, BECAUSE IT DOES EXIST' +END +ELSE +BEGIN + SELECT 'TABLE EXISTS - THIS IS CORRECT' +END +GO +~~START~~ +varchar +TABLE EXISTS - THIS IS CORRECT +~~END~~ + + +IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = lower('babel_4410_My_Table'))) +BEGIN + SELECT 'TABLE NOT EXISTS - THIS IS WRONG, BECAUSE IT DOES EXIST' +END +ELSE +BEGIN + SELECT 'TABLE EXISTS - THIS IS CORRECT' +END +GO +~~START~~ +varchar +TABLE EXISTS - THIS IS CORRECT +~~END~~ + diff --git a/test/JDBC/expected/BABEL-4484-vu-cleanup.out b/test/JDBC/expected/BABEL-4484-vu-cleanup.out new file mode 100644 index 0000000000..01ba0a9be5 --- /dev/null +++ b/test/JDBC/expected/BABEL-4484-vu-cleanup.out @@ -0,0 +1,8 @@ +DROP TABLE test_babel_4484_t1; +GO + +DROP TABLE test_babel_4484_t2; +GO + +DROP TABLE test_babel_4484_t3; +GO diff --git a/test/JDBC/expected/BABEL-4484-vu-prepare.out b/test/JDBC/expected/BABEL-4484-vu-prepare.out new file mode 100644 index 0000000000..81bcc1e47b --- /dev/null +++ b/test/JDBC/expected/BABEL-4484-vu-prepare.out @@ -0,0 +1,8 @@ +CREATE TABLE test_babel_4484_t1(ABC int, ced varchar(10)); +GO + +CREATE TABLE test_babel_4484_t2(ABC int, 您您 varchar(10)); +GO + +CREATE TABLE test_babel_4484_t3(ABC int, 您您对您对您对您对您对您对您对您对您对您您您 int); +GO diff --git a/test/JDBC/expected/BABEL-4484-vu-verify.out b/test/JDBC/expected/BABEL-4484-vu-verify.out new file mode 100644 index 0000000000..b3961349aa --- /dev/null +++ b/test/JDBC/expected/BABEL-4484-vu-verify.out @@ -0,0 +1,28 @@ +SELECT set_config('babelfishpg_tsql.enable_sll_parse_mode', 'true', false); +GO +~~START~~ +text +on +~~END~~ + + +DELETE test_babel_4484_t1 OUTPUT test_babel_4484_t1.ced FROM test_babel_4484_t1 INNER JOIN test_babel_4484_t2 ON test_babel_4484_t1.ABC = test_babel_4484_t2.ABC WHERE test_babel_4484_t1.ABC = 1; +GO +~~START~~ +varchar +~~END~~ + + +DELETE test_babel_4484_t2 OUTPUT test_babel_4484_t2.您您 FROM test_babel_4484_t2 INNER JOIN test_babel_4484_t3 ON test_babel_4484_t2.ABC = test_babel_4484_t3.ABC WHERE test_babel_4484_t2.ABC = 1; +GO +~~START~~ +varchar +~~END~~ + + +SELECT test_babel_4484_t1.ced FROM test_babel_4484_t1 INNER JOIN test_babel_4484_t2 ON test_babel_4484_t1.ABC = test_babel_4484_t2.ABC WHERE test_babel_4484_t1.ABC = 1; +GO +~~START~~ +varchar +~~END~~ + diff --git a/test/JDBC/expected/BABEL-604.out b/test/JDBC/expected/BABEL-604.out index 63c134f225..c919f688cc 100644 --- a/test/JDBC/expected/BABEL-604.out +++ b/test/JDBC/expected/BABEL-604.out @@ -12,14 +12,14 @@ call p_employee_select GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: column "p_employee_select" does not exist)~~ +~~ERROR (Message: procedure call(unknown) does not exist)~~ call p_employee_select GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: column "p_employee_select" does not exist)~~ +~~ERROR (Message: procedure call(unknown) does not exist)~~ create procedure p as select 2; select 1; diff --git a/test/JDBC/expected/BABEL-662.out b/test/JDBC/expected/BABEL-662.out index a8002b61c0..e28f76f21c 100644 --- a/test/JDBC/expected/BABEL-662.out +++ b/test/JDBC/expected/BABEL-662.out @@ -101,7 +101,7 @@ us emaster go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: column "emaster" does not exist)~~ +~~ERROR (Message: procedure us(unknown) does not exist)~~ -- BABEL-2067 diff --git a/test/JDBC/expected/BABEL-733-vu-verify.out b/test/JDBC/expected/BABEL-733-vu-verify.out index 56ccf90aff..f5b800a36d 100644 --- a/test/JDBC/expected/BABEL-733-vu-verify.out +++ b/test/JDBC/expected/BABEL-733-vu-verify.out @@ -149,6 +149,10 @@ varchar ~~END~~ +-- reset the login password +ALTER LOGIN babel_733_log1 WITH PASSWORD = '123456789'; +GO + -- tsql user=babel_733_log1 password=123456789 -- test user permissions SELECT current_user; 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/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/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-CREATE-TABLE.out b/test/JDBC/expected/BABEL-CREATE-TABLE.out new file mode 100644 index 0000000000..a1bcac1e10 --- /dev/null +++ b/test/JDBC/expected/BABEL-CREATE-TABLE.out @@ -0,0 +1,111 @@ + +-- BABEL-4433: Crashes during CREATE TABLE with ASC/DESC Keys +-- This should fail with collation error but it should not crash +CREATE TABLE [Babel4433Table1]( + [Id] [uniqueidentifier] NOT NULL, + [SequenceId] [bigint] IDENTITY(1,1) NOT NULL, + [PanelId] [uniqueidentifier] NOT NULL, + [Name] [nvarchar](400) COLLATE Latin1_General_100_CI_AS_SC NULL, + CONSTRAINT [PK_Babel4433Table1] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], + CONSTRAINT [UC_Babel4433Table1_SequenceId] UNIQUE NONCLUSTERED +( + [SequenceId] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: collation "latin1_general_100_ci_as_sc" for encoding "UTF8" does not exist)~~ + + + +----------------------------------------------------------------------- +CREATE TABLE [Babel4433Table2]( + [col1] [int] IDENTITY(1,1) NOT NULL, + [col2] [nvarchar](64) NOT NULL, + [col3] [int] NOT NULL, + [col4] [int] NOT NULL, + CONSTRAINT [PK_Babel4433Table2] PRIMARY KEY CLUSTERED +( + [col1] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], + CONSTRAINT [IX_Babel4433Table2] UNIQUE NONCLUSTERED +( + [col2] , + [col3] DESC, + [col4] +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO + +DROP TABLE [Babel4433Table2] +GO + + +----------------------------------------------------------------------- +CREATE TABLE [Babel4433Table3]( + [ID] [int] IDENTITY(1,1) NOT NULL, + [Userid] [varchar](50) NOT NULL, + CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED +( + [ID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], + CONSTRAINT [Unique_Key_Userid] UNIQUE NONCLUSTERED +( + [Userid] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +go + +DROP TABLE [Babel4433Table3] +GO + + +----------------------------------------------------------------------- +CREATE TABLE [Babel4433Table4]( + [ContainerID] [int] IDENTITY(1,1) NOT NULL, + [ContentIdentifier] [varchar](100) NOT NULL, + CONSTRAINT [PK_Babel4433Table3] PRIMARY KEY CLUSTERED +( + [ContainerID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], + CONSTRAINT [NC_Container__ContentIdentifier_UIX1] UNIQUE NONCLUSTERED +( + [ContentIdentifier] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +go + +DROP TABLE [Babel4433Table4] +GO + + +----------------------------------------------------------------------- +-- This should fail because schema does not exist but it should not crash +CREATE TABLE [Dummy].[Babel4433Table5]( + [ProcessID] [int] NOT NULL, + [Ordinal] [int] NOT NULL, + [StageKey] [varchar](64) NOT NULL, + CONSTRAINT [PK_Babel4433Table5] PRIMARY KEY CLUSTERED +( + [ProcessID] ASC, + [Ordinal] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], + CONSTRAINT [AK_ProcessStage] UNIQUE NONCLUSTERED +( + [ProcessID] ASC, + [StageKey] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: schema "master_dummy" does not exist)~~ + + + + + diff --git a/test/JDBC/expected/BABEL-CROSS-DB.out b/test/JDBC/expected/BABEL-CROSS-DB.out index bf13b5f26f..2273c92e4f 100644 --- a/test/JDBC/expected/BABEL-CROSS-DB.out +++ b/test/JDBC/expected/BABEL-CROSS-DB.out @@ -522,6 +522,12 @@ DROP PROCEDURE p1 GO -- tsql +USE db1; +GO + +DROP TABLE db1_t1; +GO + USE master; GO diff --git a/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-cleanup.out b/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-cleanup.out new file mode 100644 index 0000000000..ea28e3a018 --- /dev/null +++ b/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-cleanup.out @@ -0,0 +1,32 @@ +-- tsql +USE babel_extended_properties_db +GO + +DROP USER normal_user +GO + +DROP LOGIN normal_user +GO + +USE master +GO + +DROP DATABASE babel_extended_properties_db +GO + +DROP LOGIN owner +GO + +SELECT class, class_desc, IIF(major_id > 0, 1, 0) AS major_id, minor_id, name, value FROM sys.extended_properties +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +~~END~~ + + +SELECT dbid, schema_name, major_name, minor_name, type, name, orig_name, value FROM sys.babelfish_extended_properties ORDER BY dbid, type, schema_name, major_name, minor_name, name +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + diff --git a/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-prepare.out b/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-prepare.out new file mode 100644 index 0000000000..9fdd77f2b3 --- /dev/null +++ b/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-prepare.out @@ -0,0 +1,88 @@ +-- tsql +CREATE LOGIN owner WITH PASSWORD = '12345678' +GO + +ALTER ROLE sysadmin ADD MEMBER owner +GO + +CREATE DATABASE babel_extended_properties_db +GO + +USE babel_extended_properties_db +GO + +CREATE LOGIN normal_user WITH PASSWORD = '12345678' +GO + +CREATE USER normal_user FOR LOGIN normal_user +GO + +CREATE PROCEDURE babel_sp_addextendedproperty + @name sys.sysname, + @value sys.sql_variant = NULL, + @level0type VARCHAR(128) = NULL, + @level0name sys.sysname = NULL, + @level1type VARCHAR(128) = NULL, + @level1name sys.sysname = NULL, + @level2type VARCHAR(128) = NULL, + @level2name sys.sysname = NULL +AS +BEGIN + EXEC sp_addextendedproperty @name, @value, @level0type, @level0name, @level1type, @level1name, @level2type, @level2name +END +GO + +CREATE PROCEDURE babel_sp_updateextendedproperty + @name sys.sysname, + @value sys.sql_variant = NULL, + @level0type VARCHAR(128) = NULL, + @level0name sys.sysname = NULL, + @level1type VARCHAR(128) = NULL, + @level1name sys.sysname = NULL, + @level2type VARCHAR(128) = NULL, + @level2name sys.sysname = NULL +AS +BEGIN + EXEC sp_updateextendedproperty @name, @value, @level0type, @level0name, @level1type, @level1name, @level2type, @level2name +END +GO + +CREATE PROCEDURE babel_sp_dropextendedproperty + @name sys.sysname, + @level0type VARCHAR(128) = NULL, + @level0name sys.sysname = NULL, + @level1type VARCHAR(128) = NULL, + @level1name sys.sysname = NULL, + @level2type VARCHAR(128) = NULL, + @level2name sys.sysname = NULL +AS +BEGIN + EXEC sp_dropextendedproperty @name, @level0type, @level0name, @level1type, @level1name, @level2type, @level2name +END +GO + +CREATE PROCEDURE babel_fn_listextendedproperty + @name sys.sysname, + @level0type VARCHAR(128), + @level0name sys.sysname, + @level1type VARCHAR(128), + @level1name sys.sysname, + @level2type VARCHAR(128), + @level2name sys.sysname +AS +BEGIN + SELECT * FROM fn_listextendedproperty(@name, @level0type, @level0name, @level1type, @level1name, @level2type, @level2name) ORDER BY objtype, objname, name, value +END +GO + +CREATE VIEW babel_extended_properties_view AS +SELECT class, class_desc, IIF(major_id > 0, 1, 0) AS major_id, minor_id, name, value FROM sys.extended_properties +GO + +CREATE PROCEDURE babel_extended_properties_proc AS +SELECT class, class_desc, IIF(major_id > 0, 1, 0) AS major_id, minor_id, name, value FROM sys.extended_properties +GO + +CREATE PROCEDURE babel_babelfish_extended_properties_proc AS +SELECT IIF(bep.dbid = db_id(), 1, 0) AS dbid, (CASE WHEN bne.orig_name IS NOT NULL THEN CAST(bne.orig_name AS varchar(max)) ELSE CAST(bep.schema_name AS varchar(max)) END) as schema_name, bep.major_name, bep.minor_name, bep.type, bep.name, bep.orig_name, bep.value FROM sys.babelfish_extended_properties bep LEFT JOIN sys.babelfish_namespace_ext bne ON bep.schema_name = bne.nspname ORDER BY bep.dbid, bep.type, bne.orig_name, bep.major_name, bep.minor_name, bep.name +GO diff --git a/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-verify.out b/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-verify.out new file mode 100644 index 0000000000..98648affba --- /dev/null +++ b/test/JDBC/expected/BABEL-EXTENDEDPROPERTY-v2-vu-verify.out @@ -0,0 +1,2670 @@ +-- psql +do +$$ declare dbname text; +begin + select setting from pg_settings where name like 'babelfishpg_tsql.database_name' into dbname; + EXECUTE 'GRANT CREATE ON DATABASE ' || quote_ident(dbname) || ' TO babel_extended_properties_db_guest'; +end $$; +GO + +-- tsql +-- reset the login password +ALTER LOGIN owner WITH PASSWORD = '12345678'; +GO + +-- tsql user=owner password=12345678 +USE babel_extended_properties_db +GO + +-- should fail +EXEC babel_sp_addextendedproperty 'wrong param', 'test', '', NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: An invalid parameter or option was specified for procedure 'sp_addextendedproperty'.)~~ + + +EXEC babel_sp_updateextendedproperty 'wrong param', 'test', NULL, NULL, '', '' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: An invalid parameter or option was specified for procedure 'sp_updateextendedproperty'.)~~ + + +EXEC babel_sp_dropextendedproperty 'wrong param', 'test', '', '', NULL, NULL, '', '' +GO +~~ERROR (Code: 8144)~~ + +~~ERROR (Message: procedure babel_sp_dropextendedproperty has too many arguments specified.)~~ + + +EXEC babel_sp_updateextendedproperty 'non-existing property', 'test' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Property cannot be updated or deleted. Property 'non-existing property' does not exist for 'object specified'.)~~ + + +EXEC babel_sp_dropextendedproperty 'non-existing property' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Property cannot be updated or deleted. Property 'non-existing property' does not exist for 'object specified'.)~~ + + +EXEC babel_sp_addextendedproperty 'already existing property', 'test' +GO + +EXEC babel_sp_addextendedproperty 'already existing property', 'test' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Property cannot be added. Property 'already existing property' already exists for 'object specified'.)~~ + + +EXEC babel_sp_dropextendedproperty 'wrong param' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Property cannot be updated or deleted. Property 'wrong param' does not exist for 'object specified'.)~~ + + +EXEC babel_sp_dropextendedproperty 'wrong param', NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Property cannot be updated or deleted. Property 'wrong param' does not exist for 'object specified'.)~~ + + +EXEC babel_sp_dropextendedproperty 'already existing property' +GO + +SELECT * FROM babel_fn_listextendedproperty(NULL) +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function babel_fn_listextendedproperty expects parameter "@level0type", which was not supplied.)~~ + + +-- database +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_sp_addextendedproperty 'database property1', 'database property1 before' +GO + +EXEC babel_sp_addextendedproperty 'database property2', 'database property2 before' +GO + +EXEC babel_fn_listextendedproperty NULL, NULL, NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +#!##!#database property1#!#database property1 before +#!##!#database property2#!#database property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'database property1', NULL, NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +#!##!#database property1#!#database property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 before +0#!#DATABASE#!#0#!#0#!#database property2#!#database property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'database property1', 'database property1 after' +GO + +EXEC babel_sp_updateextendedproperty 'database property2', 'database property2 after' +GO + +EXEC babel_fn_listextendedproperty NULL, NULL, NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +#!##!#database property1#!#database property1 after +#!##!#database property2#!#database property2 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +0#!#DATABASE#!#0#!#0#!#database property2#!#database property2 after +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'database property2' +GO + +EXEC babel_fn_listextendedproperty NULL, NULL, NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +#!##!#database property1#!#database property1 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- schema +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +~~END~~ + + +CREATE SCHEMA babel_extended_properties_schema1 +GO + +EXEC babel_sp_addextendedproperty 'schema property1', 'schema property1 before', 'schema', 'babel_extended_properties_schema1' +GO + +EXEC babel_sp_addextendedproperty 'schema property2', 'schema property2 before', 'schema', 'babel_extended_properties_schema1' +GO + +CREATE SCHEMA BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name +GO + +EXEC babel_sp_addextendedproperty 'schema property1', 'schema property1 before', 'schema', 'BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_sp_addextendedproperty 'schema property2', 'schema property2 before', 'schema', 'BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SCHEMA#!#babel_extended_properties_schema1#!#schema property1#!#schema property1 before +SCHEMA#!#babel_extended_properties_schema1#!#schema property2#!#schema property2 before +SCHEMA#!#BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#schema property1#!#schema property1 before +SCHEMA#!#BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#schema property2#!#schema property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SCHEMA#!#babel_extended_properties_schema1#!#schema property1#!#schema property1 before +SCHEMA#!#babel_extended_properties_schema1#!#schema property2#!#schema property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'schema property1', 'schema', 'babel_extended_properties_schema1', NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SCHEMA#!#babel_extended_properties_schema1#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'schema property1', 'schema', NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SCHEMA#!#babel_extended_properties_schema1#!#schema property1#!#schema property1 before +SCHEMA#!#BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#schema property1#!#schema property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'schema property1', 'schema property1 after', 'schema', 'babel_extended_properties_schema1' +GO + +EXEC babel_sp_updateextendedproperty 'schema property2', 'schema property2 after', 'schema', 'BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SCHEMA#!#babel_extended_properties_schema1#!#schema property1#!#schema property1 after +SCHEMA#!#babel_extended_properties_schema1#!#schema property2#!#schema property2 before +SCHEMA#!#BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#schema property1#!#schema property1 before +SCHEMA#!#BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#schema property2#!#schema property2 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 after +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'schema property2', 'schema', 'BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, NULL, NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SCHEMA#!#babel_extended_properties_schema1#!#schema property1#!#schema property1 after +SCHEMA#!#babel_extended_properties_schema1#!#schema property2#!#schema property2 before +SCHEMA#!#BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#schema property1#!#schema property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- table +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +CREATE TABLE babel_extended_properties_schema1.babel_extended_properties_table1(id int, name varchar); +GO + +EXEC babel_sp_addextendedproperty 'table property1', 'table property1 before', 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1' +GO + +EXEC babel_sp_addextendedproperty 'table property2', 'table property2 before', 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1' +GO + +CREATE TABLE babel_extended_properties_schema1.BABEL_extended_properties_table2(Id int, LONG_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name varchar); +GO + +EXEC babel_sp_addextendedproperty 'table property1', 'table property1 before', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table2' +GO + +EXEC babel_sp_addextendedproperty 'table property2', 'table property2 before', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table2' +GO + +CREATE TABLE babel_extended_properties_schema1.BABEL_extended_properties_table3_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name(id int, name varchar); +GO + +EXEC babel_sp_addextendedproperty 'table property1', 'table property1 before', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table3_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_sp_addextendedproperty 'table property2', 'table property2 before', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table3_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, 'table', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 before +TABLE#!#babel_extended_properties_table1#!#table property2#!#table property2 before +TABLE#!#BABEL_extended_properties_table2#!#table property1#!#table property1 before +TABLE#!#BABEL_extended_properties_table2#!#table property2#!#table property2 before +TABLE#!#babel_extended_properties_table783e9cd01e68686d0d071a20f0d03eba#!#table property1#!#table property1 before +TABLE#!#babel_extended_properties_table783e9cd01e68686d0d071a20f0d03eba#!#table property2#!#table property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 before +TABLE#!#babel_extended_properties_table1#!#table property2#!#table property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'table property1', 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 before +TABLE#!#BABEL_extended_properties_table2#!#table property1#!#table property1 before +TABLE#!#babel_extended_properties_table783e9cd01e68686d0d071a20f0d03eba#!#table property1#!#table property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'table property1', 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'table property1', 'table property1 after', 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1' +GO + +EXEC babel_sp_updateextendedproperty 'table property2', 'table property2 after', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table2' +GO + +EXEC babel_sp_updateextendedproperty 'table property1', 'table property1 after', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table3_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 after +TABLE#!#babel_extended_properties_table1#!#table property2#!#table property2 before +TABLE#!#BABEL_extended_properties_table2#!#table property1#!#table property1 before +TABLE#!#BABEL_extended_properties_table2#!#table property2#!#table property2 after +TABLE#!#babel_extended_properties_table783e9cd01e68686d0d071a20f0d03eba#!#table property1#!#table property1 after +TABLE#!#babel_extended_properties_table783e9cd01e68686d0d071a20f0d03eba#!#table property2#!#table property2 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'table property2', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table2' +GO + +EXEC babel_sp_dropextendedproperty 'table property1', 'schema', 'babel_extended_properties_schema1', 'table', 'BABEL_extended_properties_table3_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 after +TABLE#!#babel_extended_properties_table1#!#table property2#!#table property2 before +TABLE#!#BABEL_extended_properties_table2#!#table property1#!#table property1 before +TABLE#!#babel_extended_properties_table783e9cd01e68686d0d071a20f0d03eba#!#table property2#!#table property2 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP TABLE babel_extended_properties_schema1.BABEL_extended_properties_table3_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 after +TABLE#!#babel_extended_properties_table1#!#table property2#!#table property2 before +TABLE#!#BABEL_extended_properties_table2#!#table property1#!#table property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- table column +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC sp_addextendedproperty 'column property1 ', 'column property1 before', 'schema ', 'babel_extended_properties_schema1 ', 'table ', 'babel_extended_properties_table1 ', 'column ', 'id ' +GO + +EXEC sp_addextendedproperty 'column property2 ', 'column property2 before', 'schema ', 'babel_extended_properties_schema1 ', 'table ', 'babel_extended_properties_table1 ', 'column ', 'name ' +GO + +EXEC sp_addextendedproperty 'column property1 ', 'column property1 before', 'SCHEMA ', 'BABEL_EXTENDED_PROPERTIES_SCHEMA1 ', 'TABLE ', 'BABEL_EXTENDED_PROPERTIES_TABLE2 ', 'COLUMN ', 'ID ' +GO + +EXEC sp_addextendedproperty 'COLUMN PROPERTY2 "{\) ', 'COLUMN PROPERTY2 BEFORE "{\) ', 'SCHEMA ', 'BABEL_EXTENDED_PROPERTIES_SCHEMA1 ', 'TABLE ', 'BABEL_EXTENDED_PROPERTIES_TABLE2 ', 'COLUMN ', 'LONG_LONG_LONG_long_long_long_long_long_long_long_long_long_long_long_long_long_name ' +GO + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', NULL, 'Table ', NULL, 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', NULL, 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table1 ', 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#id#!#column property1#!#column property1 before +COLUMN#!#name#!#column property2#!#column property2 before +~~END~~ + + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table1 ', 'Column ', 'Id ') +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#id#!#column property1#!#column property1 before +~~END~~ + + +SELECT * FROM fn_listextendedproperty('Column property1 ', 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table1 ', 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#id#!#column property1#!#column property1 before +~~END~~ + + +SELECT * FROM fn_listextendedproperty('Column property1 ', 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table1 ', 'Column ', 'Id ') +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#id#!#column property1#!#column property1 before +~~END~~ + + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table2 ', 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#Id#!#column property1#!#column property1 before +COLUMN#!#LONG_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name#!#COLUMN PROPERTY2 "{\)#!#COLUMN PROPERTY2 BEFORE "{\) +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#COLUMN PROPERTY2 "{\)#!#COLUMN PROPERTY2 BEFORE "{\) +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC sp_updateextendedproperty 'Column property1 ', 'column property1 after', 'Schema ', 'Babel_extended_properties_schema1 ', 'Table', 'Babel_extended_properties_table1 ', 'Column ', 'Id ' +GO + +EXEC sp_updateextendedproperty 'column property2 "{\) ', 'Column property2 after ', 'Schema ', 'Babel_extended_properties_schema1 ', 'Table', 'Babel_extended_properties_table2 ', 'Column ', 'LONG_long_long_LONG_long_long_long_long_long_long_long_long_long_long_long_long_name ' +GO + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table1 ', 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#id#!#column property1#!#column property1 after +COLUMN#!#name#!#column property2#!#column property2 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#COLUMN PROPERTY2 "{\)#!#Column property2 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC sp_dropextendedproperty 'Column property2 "{\) ', 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table2 ', 'Column ', 'long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name ' +GO + +SELECT * FROM fn_listextendedproperty(NULL, 'Schema ', 'Babel_extended_properties_schema1 ', 'Table ', 'Babel_extended_properties_table1 ', 'Column ', NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +COLUMN#!#id#!#column property1#!#column property1 after +COLUMN#!#name#!#column property2#!#column property2 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- view +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +CREATE VIEW babel_extended_properties_schema1.babel_extended_properties_view1 AS +SELECT * FROM babel_extended_properties_schema1.babel_extended_properties_table1 +GO + +EXEC babel_sp_addextendedproperty 'view property1', 'view property1 before', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view1' +GO + +EXEC babel_sp_addextendedproperty 'view property2', 'view property2 before', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view1' +GO + +CREATE VIEW babel_extended_properties_schema1.babel_extended_properties_view2 AS +SELECT * FROM babel_extended_properties_schema1.BABEL_extended_properties_table2 +GO + +EXEC babel_sp_addextendedproperty 'view property1', 'view property1 before', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view2' +GO + +EXEC babel_sp_addextendedproperty 'view property2', 'view property2 before', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, 'view', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'view', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +VIEW#!#babel_extended_properties_view1#!#view property1#!#view property1 before +VIEW#!#babel_extended_properties_view1#!#view property2#!#view property2 before +VIEW#!#babel_extended_properties_view2#!#view property1#!#view property1 before +VIEW#!#babel_extended_properties_view2#!#view property2#!#view property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +VIEW#!#babel_extended_properties_view1#!#view property1#!#view property1 before +VIEW#!#babel_extended_properties_view1#!#view property2#!#view property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'view property1', 'schema', 'babel_extended_properties_schema1', 'view', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +VIEW#!#babel_extended_properties_view1#!#view property1#!#view property1 before +VIEW#!#babel_extended_properties_view2#!#view property1#!#view property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'view property1', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +VIEW#!#babel_extended_properties_view1#!#view property1#!#view property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'view property1', 'view property1 after', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view1' +GO + +EXEC babel_sp_updateextendedproperty 'view property2', 'view property2 after', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'view', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +VIEW#!#babel_extended_properties_view1#!#view property1#!#view property1 after +VIEW#!#babel_extended_properties_view1#!#view property2#!#view property2 before +VIEW#!#babel_extended_properties_view2#!#view property1#!#view property1 before +VIEW#!#babel_extended_properties_view2#!#view property2#!#view property2 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'view property2', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'view', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +VIEW#!#babel_extended_properties_view1#!#view property1#!#view property1 after +VIEW#!#babel_extended_properties_view1#!#view property2#!#view property2 before +VIEW#!#babel_extended_properties_view2#!#view property1#!#view property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- sequence +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +CREATE SEQUENCE babel_extended_properties_schema1.babel_extended_properties_seq1 +GO + +EXEC babel_sp_addextendedproperty 'sequence property1', 'sequence property1 before', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq1' +GO + +EXEC babel_sp_addextendedproperty 'sequence property2', 'sequence property2 before', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq1' +GO + +CREATE SEQUENCE babel_extended_properties_schema1.babel_extended_properties_seq2 +GO + +EXEC babel_sp_addextendedproperty 'sequence property1', 'sequence property1 before', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq2' +GO + +EXEC babel_sp_addextendedproperty 'sequence property2', 'sequence property2 before', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, 'sequence', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'sequence', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property1#!#sequence property1 before +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property2#!#sequence property2 before +SEQUENCE#!#babel_extended_properties_seq2#!#sequence property1#!#sequence property1 before +SEQUENCE#!#babel_extended_properties_seq2#!#sequence property2#!#sequence property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property1#!#sequence property1 before +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property2#!#sequence property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'sequence property1', 'schema', 'babel_extended_properties_schema1', 'sequence', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property1#!#sequence property1 before +SEQUENCE#!#babel_extended_properties_seq2#!#sequence property1#!#sequence property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'sequence property1', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property1#!#sequence property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'sequence property1', 'sequence property1 after', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq1' +GO + +EXEC babel_sp_updateextendedproperty 'sequence property2', 'sequence property2 after', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'sequence', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property1#!#sequence property1 after +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property2#!#sequence property2 before +SEQUENCE#!#babel_extended_properties_seq2#!#sequence property1#!#sequence property1 before +SEQUENCE#!#babel_extended_properties_seq2#!#sequence property2#!#sequence property2 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'sequence property2', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'sequence', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property1#!#sequence property1 after +SEQUENCE#!#babel_extended_properties_seq1#!#sequence property2#!#sequence property2 before +SEQUENCE#!#babel_extended_properties_seq2#!#sequence property1#!#sequence property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- procedure +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +CREATE PROCEDURE babel_extended_properties_schema1.babel_extended_properties_proc1 +AS +BEGIN + RETURN 1 +END +GO + +EXEC babel_sp_addextendedproperty 'procedure property1', 'procedure property1 before', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc1' +GO + +EXEC babel_sp_addextendedproperty 'procedure property2', 'procedure property2 before', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc1' +GO + +CREATE PROCEDURE babel_extended_properties_schema1.babel_extended_properties_proc2 +AS +BEGIN + RETURN 1 +END +GO + +EXEC babel_sp_addextendedproperty 'procedure property1', 'procedure property1 before', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc2' +GO + +EXEC babel_sp_addextendedproperty 'procedure property2', 'procedure property2 before', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, 'procedure', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'procedure', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property1#!#procedure property1 before +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property2#!#procedure property2 before +PROCEDURE#!#babel_extended_properties_proc2#!#procedure property1#!#procedure property1 before +PROCEDURE#!#babel_extended_properties_proc2#!#procedure property2#!#procedure property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property1#!#procedure property1 before +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property2#!#procedure property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'procedure property1', 'schema', 'babel_extended_properties_schema1', 'procedure', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property1#!#procedure property1 before +PROCEDURE#!#babel_extended_properties_proc2#!#procedure property1#!#procedure property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'procedure property1', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property1#!#procedure property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'procedure property1', 'procedure property1 after', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc1' +GO + +EXEC babel_sp_updateextendedproperty 'procedure property2', 'procedure property2 after', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'procedure', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property1#!#procedure property1 after +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property2#!#procedure property2 before +PROCEDURE#!#babel_extended_properties_proc2#!#procedure property1#!#procedure property1 before +PROCEDURE#!#babel_extended_properties_proc2#!#procedure property2#!#procedure property2 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'procedure property2', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'procedure', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property1#!#procedure property1 after +PROCEDURE#!#babel_extended_properties_proc1#!#procedure property2#!#procedure property2 before +PROCEDURE#!#babel_extended_properties_proc2#!#procedure property1#!#procedure property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- function +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +CREATE FUNCTION babel_extended_properties_schema1.babel_extended_properties_func1() +RETURNS INT AS +BEGIN + RETURN 1 +END +GO + +EXEC babel_sp_addextendedproperty 'function property1', 'function property1 before', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func1' +GO + +EXEC babel_sp_addextendedproperty 'function property2', 'function property2 before', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func1' +GO + +CREATE FUNCTION babel_extended_properties_schema1.babel_extended_properties_func2() +RETURNS INT AS +BEGIN + RETURN 1 +END +GO + +EXEC babel_sp_addextendedproperty 'function property1', 'function property1 before', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func2' +GO + +EXEC babel_sp_addextendedproperty 'function property2', 'function property2 before', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, 'function', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'function', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +FUNCTION#!#babel_extended_properties_func1#!#function property1#!#function property1 before +FUNCTION#!#babel_extended_properties_func1#!#function property2#!#function property2 before +FUNCTION#!#babel_extended_properties_func2#!#function property1#!#function property1 before +FUNCTION#!#babel_extended_properties_func2#!#function property2#!#function property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +FUNCTION#!#babel_extended_properties_func1#!#function property1#!#function property1 before +FUNCTION#!#babel_extended_properties_func1#!#function property2#!#function property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'function property1', 'schema', 'babel_extended_properties_schema1', 'function', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +FUNCTION#!#babel_extended_properties_func1#!#function property1#!#function property1 before +FUNCTION#!#babel_extended_properties_func2#!#function property1#!#function property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'function property1', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +FUNCTION#!#babel_extended_properties_func1#!#function property1#!#function property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'function property1', 'function property1 after', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func1' +GO + +EXEC babel_sp_updateextendedproperty 'function property2', 'function property2 after', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'function', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +FUNCTION#!#babel_extended_properties_func1#!#function property1#!#function property1 after +FUNCTION#!#babel_extended_properties_func1#!#function property2#!#function property2 before +FUNCTION#!#babel_extended_properties_func2#!#function property1#!#function property1 before +FUNCTION#!#babel_extended_properties_func2#!#function property2#!#function property2 after +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'function property2', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'function', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +FUNCTION#!#babel_extended_properties_func1#!#function property1#!#function property1 after +FUNCTION#!#babel_extended_properties_func1#!#function property2#!#function property2 before +FUNCTION#!#babel_extended_properties_func2#!#function property1#!#function property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- type +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +~~END~~ + + +CREATE TYPE babel_extended_properties_schema1.babel_extended_properties_type1 +AS TABLE(id int) +GO + +EXEC babel_sp_addextendedproperty 'type property1', 'type property1 before', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type1' +GO + +EXEC babel_sp_addextendedproperty 'type property2', 'type property2 before', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type1' +GO + +CREATE TYPE babel_extended_properties_schema1.babel_extended_properties_type2 +AS TABLE(id int) +GO + +EXEC babel_sp_addextendedproperty 'type property1', 'type property1 before', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type2' +GO + +EXEC babel_sp_addextendedproperty 'type property2', 12345678, 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', NULL, 'type', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'type', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TYPE#!#babel_extended_properties_type1#!#type property1#!#type property1 before +TYPE#!#babel_extended_properties_type1#!#type property2#!#type property2 before +TYPE#!#babel_extended_properties_type2#!#type property1#!#type property1 before +TYPE#!#babel_extended_properties_type2#!#type property2#!#12345678 +~~END~~ + + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TYPE#!#babel_extended_properties_type1#!#type property1#!#type property1 before +TYPE#!#babel_extended_properties_type1#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'type property1', 'schema', 'babel_extended_properties_schema1', 'type', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TYPE#!#babel_extended_properties_type1#!#type property1#!#type property1 before +TYPE#!#babel_extended_properties_type2#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_fn_listextendedproperty 'type property1', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type1', NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TYPE#!#babel_extended_properties_type1#!#type property1#!#type property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +6#!#TYPE#!#1#!#0#!#type property2#!#12345678 +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_updateextendedproperty 'type property1', 'type property1 after', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type1' +GO + +EXEC babel_sp_updateextendedproperty 'type property2', 87654321, 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'type', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TYPE#!#babel_extended_properties_type1#!#type property1#!#type property1 after +TYPE#!#babel_extended_properties_type1#!#type property2#!#type property2 before +TYPE#!#babel_extended_properties_type2#!#type property1#!#type property1 before +TYPE#!#babel_extended_properties_type2#!#type property2#!#87654321 +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +6#!#TYPE#!#1#!#0#!#type property2#!#87654321 +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +EXEC babel_sp_dropextendedproperty 'type property2', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type2' +GO + +EXEC babel_fn_listextendedproperty NULL, 'schema', 'babel_extended_properties_schema1', 'type', NULL, NULL, NULL +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TYPE#!#babel_extended_properties_type1#!#type property1#!#type property1 after +TYPE#!#babel_extended_properties_type1#!#type property2#!#type property2 before +TYPE#!#babel_extended_properties_type2#!#type property1#!#type property1 before +~~END~~ + + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- sp_rename +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + + +-- sp_rename type is not supported, so we can only drop babel_extended_properties_type2 +-- sp_rename 'babel_extended_properties_schema1.babel_extended_properties_type2', 'babel_extended_properties_type3', 'USERDATATYPE' +-- GO +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +sp_rename 'babel_extended_properties_schema1.babel_extended_properties_func2', 'babel_extended_properties_func3', 'OBJECT' +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +sp_rename 'babel_extended_properties_schema1.babel_extended_properties_proc2', 'babel_extended_properties_proc3', 'OBJECT' +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +sp_rename 'babel_extended_properties_schema1.babel_extended_properties_seq2', 'babel_extended_properties_seq3', 'OBJECT' +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +sp_rename 'babel_extended_properties_schema1.babel_extended_properties_view2', 'babel_extended_properties_view3', 'OBJECT' +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +sp_rename 'babel_extended_properties_schema1.BABEL_extended_properties_table2.Id', 'id1', 'COLUMN' +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +sp_rename 'babel_extended_properties_schema1.BABEL_extended_properties_table2', 'babel_extended_properties_table3', 'OBJECT' +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- drop object +EXEC babel_extended_properties_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 before +~~END~~ + + +-- sp_rename type failed, so we can only drop babel_extended_properties_type2 +DROP TYPE babel_extended_properties_schema1.babel_extended_properties_type2 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP FUNCTION babel_extended_properties_schema1.babel_extended_properties_func3 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP PROCEDURE babel_extended_properties_schema1.babel_extended_properties_proc3 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP SEQUENCE babel_extended_properties_schema1.babel_extended_properties_seq3 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP VIEW babel_extended_properties_schema1.babel_extended_properties_view3 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +ALTER TABLE babel_extended_properties_schema1.babel_extended_properties_table3 DROP id1 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP TABLE babel_extended_properties_schema1.babel_extended_properties_table3 +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +DROP SCHEMA BABEL_extended_properties_schema2_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_long_name +GO + +SELECT * FROM babel_extended_properties_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property1#!#view property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#view property2#!#view property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property1#!#sequence property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#sequence property2#!#sequence property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property1#!#procedure property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#procedure property2#!#procedure property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property1#!#function property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#function property2#!#function property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +6#!#TYPE#!#1#!#0#!#type property1#!#type property1 after +6#!#TYPE#!#1#!#0#!#type property2#!#type property2 before +~~END~~ + + +EXEC babel_babelfish_extended_properties_proc +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- reset the login password +ALTER LOGIN normal_user WITH PASSWORD = '12345678'; +GO + +-- tsql user=normal_user password=12345678 +USE babel_extended_properties_db +GO + +-- normal_user should fail to execute sp_xxxxextendedproperty +sp_addextendedproperty 'database property3', 'database property3 before' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "object specified" because it does not exist or you do not have permissions.)~~ + + +sp_updateextendedproperty 'schema property3', 'schema property3 before', 'schema', 'babel_extended_properties_schema1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1" because it does not exist or you do not have permissions.)~~ + + +sp_dropextendedproperty 'table property3', 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_table1" because it does not exist or you do not have permissions.)~~ + + +sp_addextendedproperty 'column property3', 'column property3 before', 'schema', 'babel_extended_properties_schema1', 'table', 'babel_extended_properties_table1', 'column', 'id' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_table1" because it does not exist or you do not have permissions.)~~ + + +sp_updateextendedproperty 'view property3', 'view property3 before', 'schema', 'babel_extended_properties_schema1', 'view', 'babel_extended_properties_view1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_view1" because it does not exist or you do not have permissions.)~~ + + +sp_dropextendedproperty 'sequence property3', 'schema', 'babel_extended_properties_schema1', 'sequence', 'babel_extended_properties_seq1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_seq1" because it does not exist or you do not have permissions.)~~ + + +sp_addextendedproperty 'procedure property3', 'procedure property3 before', 'schema', 'babel_extended_properties_schema1', 'procedure', 'babel_extended_properties_proc1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_proc1" because it does not exist or you do not have permissions.)~~ + + +sp_updateextendedproperty 'function property3', 'function property3 before', 'schema', 'babel_extended_properties_schema1', 'function', 'babel_extended_properties_func1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_func1" because it does not exist or you do not have permissions.)~~ + + +sp_dropextendedproperty 'type property3', 'schema', 'babel_extended_properties_schema1', 'type', 'babel_extended_properties_type1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the object "babel_extended_properties_schema1.babel_extended_properties_type1" because it does not exist or you do not have permissions.)~~ + + +-- tsql user=owner password=12345678 +USE babel_extended_properties_db +GO + +GRANT SELECT ON babel_extended_properties_schema1.babel_extended_properties_table1 TO normal_user +GO + +-- tsql user=normal_user password=12345678 +-- normal_user can get result from fn_listextendedproperty and sys.extended_properties after being granted +USE babel_extended_properties_db +GO + +SELECT * FROM fn_listextendedproperty(NULL, 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +TABLE#!#babel_extended_properties_table1#!#table property1#!#table property1 after +TABLE#!#babel_extended_properties_table1#!#table property2#!#table property2 before +~~END~~ + + +SELECT class, class_desc, IIF(major_id > 0, 1, 0) AS major_id, minor_id, name, value FROM sys.extended_properties +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property1#!#table property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#0#!#table property2#!#table property2 before +1#!#OBJECT_OR_COLUMN#!#1#!#1#!#column property1#!#column property1 after +1#!#OBJECT_OR_COLUMN#!#1#!#2#!#column property2#!#column property2 before +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +~~END~~ + + +-- tsql user=owner password=12345678 +USE babel_extended_properties_db +GO + +REVOKE SELECT ON babel_extended_properties_schema1.babel_extended_properties_table1 FROM normal_user +GO + +-- tsql user=normal_user password=12345678 +-- normal_user can't get result from fn_listextendedproperty and sys.extended_properties after being revoked +SELECT * FROM fn_listextendedproperty(NULL, 'schema', 'babel_extended_properties_schema1', 'table', NULL, NULL, NULL) +GO +~~START~~ +varchar#!#varchar#!#varchar#!#sql_variant +~~END~~ + + +SELECT class, class_desc, IIF(major_id > 0, 1, 0) AS major_id, minor_id, name, value FROM sys.extended_properties +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#varchar#!#sql_variant +0#!#DATABASE#!#0#!#0#!#database property1#!#database property1 after +3#!#SCHEMA#!#1#!#0#!#schema property1#!#schema property1 after +3#!#SCHEMA#!#1#!#0#!#schema property2#!#schema property2 before +~~END~~ + + +select * from sys.babelfish_extended_properties; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babelfish_extended_properties)~~ + + +-- psql +do +$$ declare dbname text; +begin + select setting from pg_settings where name like 'babelfishpg_tsql.database_name' into dbname; + EXECUTE 'REVOKE CREATE ON DATABASE ' || quote_ident(dbname) || ' FROM babel_extended_properties_db_guest'; +end $$; +GO diff --git a/test/JDBC/expected/BABEL-GRANT.out b/test/JDBC/expected/BABEL-GRANT.out index e1c4007985..d3f48b241f 100644 --- a/test/JDBC/expected/BABEL-GRANT.out +++ b/test/JDBC/expected/BABEL-GRANT.out @@ -20,6 +20,10 @@ GO --- --- Prepare Objects --- +---- SCHEMA +CREATE SCHEMA scm; +GO + ---- TABLE CREATE TABLE t1 ( a int, b int); GO @@ -57,9 +61,27 @@ GO --- --- Basic Grant / Revoke --- +GRANT SELECT ON SCHEMA::scm TO guest; +GO + +GRANT SELECT ON SCHEMA::scm TO PUBLIC; +GO + +REVOKE SELECT ON SCHEMA::scm FROM PUBLIC; +GO + +GRANT INSERT ON SCHEMA::scm TO guest; +GO + GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION; GO +GRANT ALL ON OBJECT::t1 TO PUBLIC; +GO + +REVOKE ALL ON OBJECT::t1 FROM PUBLIC; +GO + GRANT ALL ON OBJECT::seq_tinyint TO guest WITH GRANT OPTION; GO @@ -69,6 +91,12 @@ GO GRANT ALL ON OBJECT::my_func TO guest WITH GRANT OPTION; GO +GRANT EXECUTE ON OBJECT::my_func TO PUBLIC; +GO + +REVOKE EXECUTE ON OBJECT::my_func FROM PUBLIC; +GO + GRANT ALL ON OBJECT::my_proc TO guest WITH GRANT OPTION; GO @@ -143,6 +171,9 @@ GO ~~ERROR (Message: 'REVOKE ALL on Database' is not currently supported in Babelfish)~~ +REVOKE SELECT ON SCHEMA::scm FROM guest; +GO + GRANT SHOWPLAN ON OBJECT::t1 TO guest; -- unsupported permission GO ~~ERROR (Code: 33557097)~~ @@ -161,14 +192,14 @@ GRANT ALL ON SCHEMA::scm TO guest; -- unsupported class GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'GRANT ON SCHEMA' is not currently supported in Babelfish)~~ +~~ERROR (Message: The all permission has been deprecated and is not available for this class of entity.)~~ REVOKE ALL ON SCHEMA::scm TO guest; -- unsupported class GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'REVOKE ON SCHEMA' is not currently supported in Babelfish)~~ +~~ERROR (Message: The all permission has been deprecated and is not available for this class of entity.)~~ GRANT ALL ON OBJECT::t1 TO guest WITH GRANT OPTION AS superuser; @@ -178,6 +209,18 @@ GO ~~ERROR (Message: 'GRANT AS' is not currently supported in Babelfish)~~ +GRANT SELECT ON t1 TO PUBLIC; +GO + +REVOKE SELECT ON t1 FROM PUBLIC; +GO + +GRANT EXECUTE ON my_func TO PUBLIC; +GO + +REVOKE EXECUTE ON my_func FROM PUBLIC; +GO + REVOKE ALL ON OBJECT::t1 TO guest AS superuser; GO ~~ERROR (Code: 33557097)~~ @@ -189,6 +232,9 @@ GO --- --- Clean Up --- +DROP SCHEMA scm; +GO + DROP VIEW IF EXISTS my_view; GO diff --git a/test/JDBC/expected/BABEL-LIKE2ILIKE.out b/test/JDBC/expected/BABEL-LIKE2ILIKE.out index 5046da74cd..b796f3912d 100644 --- a/test/JDBC/expected/BABEL-LIKE2ILIKE.out +++ b/test/JDBC/expected/BABEL-LIKE2ILIKE.out @@ -179,9 +179,9 @@ p2 as (select c3 from like_tesing1 where c3 LIKE 'äƀ__') select * from p1 union all select * from p2 GO ~~START~~ -varchar -äb?D -ä?Cd +nvarchar +äbĆD +äƀCd ~~END~~ -- test case expression diff --git a/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out b/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out index d93ac02abd..7cdcd6eb1e 100644 --- a/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out +++ b/test/JDBC/expected/BABEL-LOGIN-USER-EXT.out @@ -690,18 +690,18 @@ ORDER BY rolname; GO ~~START~~ varchar#!#nvarchar#!#varchar#!#nvarchar#!#nvarchar -db1_guest#!#guest#!##!#db1#!# +db1_guest#!#guest#!##!#db1#!#guest db_owner#!#db_owner#!##!#db1#!# dbo#!#dbo#!##!#db1#!#dbo master_db_owner#!#db_owner#!##!#master#!# master_dbo#!#dbo#!##!#master#!#dbo -master_guest#!#guest#!##!#master#!# +master_guest#!#guest#!##!#master#!#guest msdb_db_owner#!#db_owner#!##!#msdb#!# msdb_dbo#!#dbo#!##!#msdb#!#dbo -msdb_guest#!#guest#!##!#msdb#!# +msdb_guest#!#guest#!##!#msdb#!#guest tempdb_db_owner#!#db_owner#!##!#tempdb#!# tempdb_dbo#!#dbo#!##!#tempdb#!#dbo -tempdb_guest#!#guest#!##!#tempdb#!# +tempdb_guest#!#guest#!##!#tempdb#!#guest ~~END~~ @@ -865,13 +865,13 @@ GO varchar#!#nvarchar#!#varchar#!#nvarchar#!#nvarchar master_db_owner#!#db_owner#!##!#master#!# master_dbo#!#dbo#!##!#master#!#dbo -master_guest#!#guest#!##!#master#!# +master_guest#!#guest#!##!#master#!#guest msdb_db_owner#!#db_owner#!##!#msdb#!# msdb_dbo#!#dbo#!##!#msdb#!#dbo -msdb_guest#!#guest#!##!#msdb#!# +msdb_guest#!#guest#!##!#msdb#!#guest tempdb_db_owner#!#db_owner#!##!#tempdb#!# tempdb_dbo#!#dbo#!##!#tempdb#!#dbo -tempdb_guest#!#guest#!##!#tempdb#!# +tempdb_guest#!#guest#!##!#tempdb#!#guest ~~END~~ @@ -935,19 +935,19 @@ GO varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar db1_db_owner#!##!#db_owner#!#db1#!# db1_dbo#!##!#dbo#!#db1#!#dbo -db1_guest#!##!#guest#!#db1#!# +db1_guest#!##!#guest#!#db1#!#guest db2_db_owner#!##!#db_owner#!#db2#!# db2_dbo#!##!#dbo#!#db2#!#dbo -db2_guest#!##!#guest#!#db2#!# +db2_guest#!##!#guest#!#db2#!#guest master_db_owner#!##!#db_owner#!#master#!# master_dbo#!##!#dbo#!#master#!#dbo -master_guest#!##!#guest#!#master#!# +master_guest#!##!#guest#!#master#!#guest msdb_db_owner#!##!#db_owner#!#msdb#!# msdb_dbo#!##!#dbo#!#msdb#!#dbo -msdb_guest#!##!#guest#!#msdb#!# +msdb_guest#!##!#guest#!#msdb#!#guest tempdb_db_owner#!##!#db_owner#!#tempdb#!# tempdb_dbo#!##!#dbo#!#tempdb#!#dbo -tempdb_guest#!##!#guest#!#tempdb#!# +tempdb_guest#!##!#guest#!#tempdb#!#guest ~~END~~ @@ -957,9 +957,12 @@ ORDER BY default_schema_name DESC, name; GO ~~START~~ varchar#!#varchar +guest#!#guest dbo#!#dbo db_owner#!# -guest#!# +INFORMATION_SCHEMA#!# +public#!# +sys#!# ~~END~~ @@ -986,9 +989,12 @@ ORDER BY default_schema_name DESC, name; GO ~~START~~ varchar#!#varchar +guest#!#guest dbo#!#dbo db_owner#!# -guest#!# +INFORMATION_SCHEMA#!# +public#!# +sys#!# ~~END~~ @@ -1121,16 +1127,16 @@ GO varchar#!#nvarchar#!#varchar#!#nvarchar#!#nvarchar db2_db_owner#!#db_owner#!##!#db2#!# db2_dbo#!#dbo#!##!#db2#!#dbo -db2_guest#!#guest#!##!#db2#!# +db2_guest#!#guest#!##!#db2#!#guest master_db_owner#!#db_owner#!##!#master#!# master_dbo#!#dbo#!##!#master#!#dbo -master_guest#!#guest#!##!#master#!# +master_guest#!#guest#!##!#master#!#guest msdb_db_owner#!#db_owner#!##!#msdb#!# msdb_dbo#!#dbo#!##!#msdb#!#dbo -msdb_guest#!#guest#!##!#msdb#!# +msdb_guest#!#guest#!##!#msdb#!#guest tempdb_db_owner#!#db_owner#!##!#tempdb#!# tempdb_dbo#!#dbo#!##!#tempdb#!#dbo -tempdb_guest#!#guest#!##!#tempdb#!# +tempdb_guest#!#guest#!##!#tempdb#!#guest ~~END~~ @@ -1145,13 +1151,13 @@ GO varchar#!#nvarchar#!#varchar#!#nvarchar#!#nvarchar master_db_owner#!#db_owner#!##!#master#!# master_dbo#!#dbo#!##!#master#!#dbo -master_guest#!#guest#!##!#master#!# +master_guest#!#guest#!##!#master#!#guest msdb_db_owner#!#db_owner#!##!#msdb#!# msdb_dbo#!#dbo#!##!#msdb#!#dbo -msdb_guest#!#guest#!##!#msdb#!# +msdb_guest#!#guest#!##!#msdb#!#guest tempdb_db_owner#!#db_owner#!##!#tempdb#!# tempdb_dbo#!#dbo#!##!#tempdb#!#dbo -tempdb_guest#!#guest#!##!#tempdb#!# +tempdb_guest#!#guest#!##!#tempdb#!#guest ~~END~~ 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..e6a4962752 100644 --- a/test/JDBC/expected/BABEL-LOGIN-vu-verify.out +++ b/test/JDBC/expected/BABEL-LOGIN-vu-verify.out @@ -5,6 +5,10 @@ go CREATE USER babel_login_vu_prepare_r2 WITH DEFAULT_SCHEMA = babel_login_vu_prepare_sch; go +-- reset the login password +ALTER LOGIN babel_login_vu_prepare_r1 WITH PASSWORD = 'abc'; +go + -- tsql user=babel_login_vu_prepare_r1 password=abc -- Login with a Babelfish user should succeed SELECT db_name(); @@ -91,6 +95,11 @@ master_babel_login_vu_prepare_r2#!#babel_login_vu_prepare_r2#!#babel_login_vu_pr ~~END~~ +-- tsql +-- reset the login password +ALTER LOGIN babel_login_vu_prepare_r2 WITH password = 'abc'; +go + -- tsql user=babel_login_vu_prepare_r2 password=abc SELECT db_name(); go @@ -278,6 +287,10 @@ go CREATE USER babel_login_vu_prepare_err_user; go +-- reset the login password +ALTER LOGIN babel_login_vu_prepare_err_user WITH PASSWORD = '123'; +go + -- tsql user=babel_login_vu_prepare_err_user password=123 -- Should fail, does not have permission to alter sysadmin ALTER SERVER ROLE sysadmin ADD MEMBER babel_login_vu_prepare_err_user @@ -460,3 +473,143 @@ 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 + +-- reset the login password +ALTER LOGIN babel_4080_nonsysadmin1 with PASSWORD = '1234'; +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 +~~END~~ + + +ALTER LOGIN babel_4080_testlogin1 DISABLE; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot alter the login 'babel_4080_testlogin1', because it does not exist or you do not have permission.)~~ + + +ALTER LOGIN babel_4080_testlogin1 WITH PASSWORD = 'newpassword'; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot alter the login 'babel_4080_testlogin1', because it does not exist or you do not have permission.)~~ + + +DROP LOGIN babel_4080_testlogin1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot drop the login 'babel_4080_testlogin1', because it does not exist or you do not have permission.)~~ + + +-- tsql +-- reset the login password +ALTER LOGIN babel_4080_sysadmin1 with PASSWORD = '1234'; +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 +~~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 +-- reset the login password +ALTER LOGIN babel_4080_testlogin2 with PASSWORD = '1234'; +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/expected/BABEL-ROLE-MEMBER-vu-verify.out b/test/JDBC/expected/BABEL-ROLE-MEMBER-vu-verify.out index 3e2516269f..3d55340c26 100644 --- a/test/JDBC/expected/BABEL-ROLE-MEMBER-vu-verify.out +++ b/test/JDBC/expected/BABEL-ROLE-MEMBER-vu-verify.out @@ -439,6 +439,10 @@ int ~~END~~ +-- reset the login password +ALTER LOGIN BABEL_ROLE_MEMBER_vu_prepare_login1 WITH PASSWORD = '123' +GO + -- tsql user=BABEL_ROLE_MEMBER_vu_prepare_login1 password=123 -- Connect with different logins to test membership view permission -- Test on user1 @@ -510,6 +514,11 @@ int USE master GO +-- tsql +-- reset the login password +ALTER LOGIN BABEL_ROLE_MEMBER_vu_prepare_login2 WITH PASSWORD = '123' +GO + -- tsql user=BABEL_ROLE_MEMBER_vu_prepare_login2 password=123 -- Test on user2 USE BABEL_ROLE_MEMBER_vu_prepare_db @@ -587,6 +596,11 @@ int USE master GO +-- tsql +-- reset the login password +ALTER LOGIN BABEL_ROLE_MEMBER_vu_prepare_login3 WITH PASSWORD = '123' +GO + -- tsql user=BABEL_ROLE_MEMBER_vu_prepare_login3 password=123 -- Test on user3 USE BABEL_ROLE_MEMBER_vu_prepare_db diff --git a/test/JDBC/expected/BABEL-ROLE-vu-verify.out b/test/JDBC/expected/BABEL-ROLE-vu-verify.out index 277445a2d1..515bf0533c 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 @@ -242,6 +256,10 @@ babel_role_vu_prepare_role2#!#R#!#babel_role_vu_prepare_user3#!#S ~~END~~ +-- reset the login password +ALTER LOGIN babel_role_vu_prepare_login2 WITH PASSWORD = 'abc' +GO + -- tsql user=babel_role_vu_prepare_login2 password=abc -- DB user is disallowed to add/drop itself to/from a role USE babel_role_vu_prepare_db diff --git a/test/JDBC/expected/BABEL-SESSION.out b/test/JDBC/expected/BABEL-SESSION.out index 62c2b670c0..6e9888edd5 100644 --- a/test/JDBC/expected/BABEL-SESSION.out +++ b/test/JDBC/expected/BABEL-SESSION.out @@ -45,6 +45,40 @@ GO USE master; GO +SELECT db_name(); +GO +~~START~~ +nvarchar +master +~~END~~ + + +USE tempdb; +GO + +SELECT db_name(); +GO +~~START~~ +nvarchar +tempdb +~~END~~ + + +USE msdb; +GO + +SELECT db_name(); +GO +~~START~~ +nvarchar +msdb +~~END~~ + + +USE master; +GO + + -- tsql user=r1 password=abc USE db1; GO @@ -119,6 +153,21 @@ USE master; GO -- tsql +USE db1; +GO + +DROP TABLE tb1; +GO + +DROP TABLE janedoe_schema.t1; +GO + +DROP SCHEMA janedoe_schema; +GO + +USE master; +go + DROP DATABASE db1; GO diff --git a/test/JDBC/expected/BABEL-SPCOLUMNS-vu-cleanup.out b/test/JDBC/expected/BABEL-SPCOLUMNS-vu-cleanup.out index 300741aa22..189ba7bb7c 100644 --- a/test/JDBC/expected/BABEL-SPCOLUMNS-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-SPCOLUMNS-vu-cleanup.out @@ -5,6 +5,7 @@ drop table babel_sp_columns_vu_prepare_t_int drop table babel_sp_columns_vu_prepare_t_text drop table babel_sp_columns_vu_prepare_t_time drop table babel_sp_columns_vu_prepare_t_money +drop table babel_sp_columns_vu_prepare_bytea GO USE master diff --git a/test/JDBC/expected/BABEL-SPCOLUMNS-vu-prepare.out b/test/JDBC/expected/BABEL-SPCOLUMNS-vu-prepare.out index d4e182607d..d78d53a476 100644 --- a/test/JDBC/expected/BABEL-SPCOLUMNS-vu-prepare.out +++ b/test/JDBC/expected/BABEL-SPCOLUMNS-vu-prepare.out @@ -15,3 +15,6 @@ GO CREATE table babel_sp_columns_vu_prepare_t_money(a money) GO + +CREATE table babel_sp_columns_vu_prepare_bytea(a bytea, b image) +GO diff --git a/test/JDBC/expected/BABEL-SPCOLUMNS-vu-verify.out b/test/JDBC/expected/BABEL-SPCOLUMNS-vu-verify.out index 7d6e857c87..7f3a728e80 100644 --- a/test/JDBC/expected/BABEL-SPCOLUMNS-vu-verify.out +++ b/test/JDBC/expected/BABEL-SPCOLUMNS-vu-verify.out @@ -124,3 +124,13 @@ GO varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint#!#smallint#!#varchar#!#nvarchar#!#smallint#!#smallint#!#int#!#int#!#varchar#!#smallint#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#int ~~END~~ + +-- test sp_columns_100 for bytea +EXEC [sys].sp_columns_100 'babel_sp_columns_vu_prepare_bytea', 'dbo', NULL, NULL, @ODBCVer = 3, @fUsePattern = 1; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint#!#smallint#!#varchar#!#nvarchar#!#smallint#!#smallint#!#int#!#int#!#varchar#!#smallint#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#int +babel_sp_columns_vu_prepare_mydb1#!#dbo#!#babel_sp_columns_vu_prepare_bytea#!#a#!#-4#!#bytea#!#0#!#-1#!##!##!#1#!##!##!#-4#!##!##!#1#!#YES#!#0#!#0#!#0#!#0#!##!##!##!##!##!##!#34 +babel_sp_columns_vu_prepare_mydb1#!#dbo#!#babel_sp_columns_vu_prepare_bytea#!#b#!#-4#!#image#!#2147483647#!#2147483647#!##!##!#1#!##!##!#-4#!##!#2147483647#!#2#!#YES#!#0#!#0#!#0#!#0#!##!##!##!##!##!##!#34 +~~END~~ + diff --git a/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out b/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out index 9a423f7f41..e5f0ea14aa 100644 --- a/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out +++ b/test/JDBC/expected/BABEL-SP_COLUMN_PRIVILEGES.out @@ -203,33 +203,65 @@ db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ --- Delimiter table tests: NOTE: These produces errors due to BABEL-2883 +-- Delimiter table tests exec sp_column_privileges @table_name = [mytable4] GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable4" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_column_privileges @table_name = [MYTABLE4] GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable4" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_a#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable4#!#MyColumn_b#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_column_privileges @table_name = [mytable5] GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_column_privileges @table_name = [MYTABLE5] GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_a#!#dbo#!#dbo#!#UPDATE#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable5#!#MyColumn_b#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ -- tests wildcard patterns @@ -263,11 +295,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 +314,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 +325,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_DATABASES.out b/test/JDBC/expected/BABEL-SP_DATABASES.out index 6e274e4e2f..6add03355e 100644 --- a/test/JDBC/expected/BABEL-SP_DATABASES.out +++ b/test/JDBC/expected/BABEL-SP_DATABASES.out @@ -21,33 +21,44 @@ 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~~ -EXEC sp_databases; +CREATE PROCEDURE sp_databases_PROC1 +AS +BEGIN + SET NOCOUNT ON; + DECLARE @tmp_sp_addrole TABLE(database_name sys.SYSNAME, database_size int, remarks sys.VARCHAR(254)); + INSERT INTO @tmp_sp_addrole (database_name, database_size, remarks) EXEC sp_databases; + SELECT database_name, (case when database_size >=0 then 1 else NULL end), remarks FROM @tmp_sp_addrole where database_name='DB1'; + SET NOCOUNT OFF; +END +GO + +exec sp_databases_PROC1; GO ~~START~~ varchar#!#int#!#varchar -db1#!#8#!# -master#!#0#!# -msdb#!#0#!# -tempdb#!#0#!# +db1#!#1#!# ~~END~~ +DROP PROCEDURE sp_databases_PROC1; +GO + drop table t_spdatabases; go use master; diff --git a/test/JDBC/expected/BABEL-SP_FKEYS-vu-verify.out b/test/JDBC/expected/BABEL-SP_FKEYS-vu-verify.out index 8e7afd9cd4..1a942c49bf 100644 --- a/test/JDBC/expected/BABEL-SP_FKEYS-vu-verify.out +++ b/test/JDBC/expected/BABEL-SP_FKEYS-vu-verify.out @@ -139,47 +139,63 @@ babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUm babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_b#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 ~~END~~ --- Delimiter table tests NOTE: THese do not procude correct output due to BABEL-2883 +-- Delimiter table tests exec sp_fkeys @pktable_name = [babel_sp_fkeys_vu_prepare_mytable5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_fkeys_vu_prepare_mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_a#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_b#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @pktable_name = [babel_sp_fkeys_vu_prepare_MYTABLE5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_fkeys_vu_prepare_mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_a#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_b#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [babel_sp_fkeys_vu_prepare_mytable6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_fkeys_vu_prepare_mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [babel_sp_fkeys_vu_prepare_MYTABLE6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_fkeys_vu_prepare_mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable6_column_c_column_d_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [babel_sp_fkeys_vu_prepare_mytable7] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_fkeys_vu_prepare_mytable7" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_a#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_b#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [babel_sp_fkeys_vu_prepare_MYTABLE7] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_fkeys_vu_prepare_mytable7" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#cOlUmN_a#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_a#!#1#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable5#!#CoLuMn_b#!#babel_sp_fkeys_vu_prepare_db1#!#dbo#!#babel_sp_fkeys_vu_prepare_mytable7#!#MyColumn_b#!#2#!#1#!#1#!#babel_sp_fkeys_vu_prepare_mytable7_mycolumn_a_mycolumn_b_fkey#!#babel_sp_fkeys_vu_prepare_mytable5_pkey#!#7 +~~END~~ use master diff --git a/test/JDBC/expected/BABEL-SP_FKEYS.out b/test/JDBC/expected/BABEL-SP_FKEYS.out index bc07ca059e..59bab15b99 100644 --- a/test/JDBC/expected/BABEL-SP_FKEYS.out +++ b/test/JDBC/expected/BABEL-SP_FKEYS.out @@ -155,47 +155,63 @@ db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable7#!#MyColumn_a#!#1#!#1#!#1# db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable7#!#MyColumn_b#!#2#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 ~~END~~ --- Delimiter table tests NOTE: THese do not procude correct output due to BABEL-2883 +-- Delimiter table tests exec sp_fkeys @pktable_name = [mytable5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable7#!#MyColumn_a#!#1#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable7#!#MyColumn_b#!#2#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @pktable_name = [MYTABLE5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable7#!#MyColumn_a#!#1#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable7#!#MyColumn_b#!#2#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [mytable6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [MYTABLE6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable6#!#cOlUmN_c#!#1#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable6#!#CoLuMn_d#!#2#!#1#!#1#!#mytable6_column_c_column_d_fkey#!#mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [mytable7] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable7" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable7#!#MyColumn_a#!#1#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable7#!#MyColumn_b#!#2#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +~~END~~ exec sp_fkeys @fktable_name = [MYTABLE7] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable7" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#smallint#!#smallint#!#smallint#!#varchar#!#varchar#!#smallint +db1#!#dbo#!#mytable5#!#cOlUmN_a#!#db1#!#dbo#!#mytable7#!#MyColumn_a#!#1#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +db1#!#dbo#!#mytable5#!#CoLuMn_b#!#db1#!#dbo#!#mytable7#!#MyColumn_b#!#2#!#1#!#1#!#mytable7_mycolumn_a_mycolumn_b_fkey#!#mytable5_pkey#!#7 +~~END~~ -- ensure that only tables from the same database are retrieved diff --git a/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-prepare.out b/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-prepare.out index 0c74a51458..a403b7bdef 100644 --- a/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-prepare.out +++ b/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-prepare.out @@ -131,10 +131,10 @@ GO CREATE TABLE dbo.tidentityintbigmulti ( data_type_test CHAR(50) NULL - , test_scenario CHAR(60) NULL + , test_scenario CHAR(60) NOT NULL , value_test BIGINT IDENTITY (202202081842, 100 ) NOT NULL , inserted_dt DATETIME DEFAULT GETDATE() - , user_login CHAR(255) DEFAULT CURRENT_USER + , user_login CHAR(255) DEFAULT CURRENT_USER NOT NULL ) GO CREATE UNIQUE NONCLUSTERED INDEX dbo_tidentityintbigmulti_value_test ON dbo.tidentityintbigmulti (user_login ASC, value_test ASC, test_scenario ASC); diff --git a/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-verify.out b/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-verify.out index 80c07a3e88..8431d66c2e 100644 --- a/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-verify.out +++ b/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS-vu-verify.out @@ -88,33 +88,41 @@ smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint ~~END~~ --- Delimiter table tests NOTE: These to do not produce correct output due to BABEL-2883 +-- Delimiter table tests exec sp_special_columns @table_name = [babel_sp_special_columns_vu_prepare_mytable1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_special_columns_vu_prepare_mytable1" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#4#!#babel_sp_special_columns_vu_prepare_eyedees#!#10#!#4#!#0#!#1 +1#!#ColB#!#12#!#babel_sp_special_columns_vu_prepare_phone_num#!#11#!#11#!##!#1 +~~END~~ exec sp_special_columns @table_name = [babel_sp_special_columns_vu_prepare_MYTABLE1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_special_columns_vu_prepare_mytable1" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#4#!#babel_sp_special_columns_vu_prepare_eyedees#!#10#!#4#!#0#!#1 +1#!#ColB#!#12#!#babel_sp_special_columns_vu_prepare_phone_num#!#11#!#11#!##!#1 +~~END~~ exec sp_special_columns @table_name = [babel_sp_special_columns_vu_prepare_mytable2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_special_columns_vu_prepare_mytable2" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#12#!#babel_sp_special_columns_vu_prepare_phone_num#!#11#!#11#!##!#1 +1#!#ColB#!#4#!#babel_sp_special_columns_vu_prepare_eyedees#!#10#!#4#!#0#!#1 +~~END~~ exec sp_special_columns @table_name = [babel_sp_special_columns_vu_prepare_MYTABLE2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_special_columns_vu_prepare_mytable2" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#12#!#babel_sp_special_columns_vu_prepare_phone_num#!#11#!#11#!##!#1 +1#!#ColB#!#4#!#babel_sp_special_columns_vu_prepare_eyedees#!#10#!#4#!#0#!#1 +~~END~~ -- unnamed invocation diff --git a/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS.out b/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS.out index f16c9bd670..c0385879a8 100644 --- a/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS.out +++ b/test/JDBC/expected/BABEL-SP_SPECIAL_COLUMNS.out @@ -208,33 +208,41 @@ smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint ~~END~~ --- Delimiter table tests NOTE: These to do not produce correct output due to BABEL-2883 +-- Delimiter table tests exec sp_special_columns @table_name = [mytable1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable1" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#4#!#eyedees#!#10#!#4#!#0#!#1 +1#!#ColB#!#12#!#phone_num#!#11#!#11#!##!#1 +~~END~~ exec sp_special_columns @table_name = [MYTABLE1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable1" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#4#!#eyedees#!#10#!#4#!#0#!#1 +1#!#ColB#!#12#!#phone_num#!#11#!#11#!##!#1 +~~END~~ exec sp_special_columns @table_name = [mytable2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable2" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#12#!#phone_num#!#11#!#11#!##!#1 +1#!#ColB#!#4#!#eyedees#!#10#!#4#!#0#!#1 +~~END~~ exec sp_special_columns @table_name = [MYTABLE2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable2" does not exist)~~ +~~START~~ +smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint +1#!#ColA#!#12#!#phone_num#!#11#!#11#!##!#1 +1#!#ColB#!#4#!#eyedees#!#10#!#4#!#0#!#1 +~~END~~ -- unnamed invocation @@ -614,10 +622,10 @@ smallint#!#varchar#!#smallint#!#varchar#!#int#!#int#!#smallint#!#smallint CREATE TABLE dbo.tidentityintbigmulti ( data_type_test CHAR(50) NULL - , test_scenario CHAR(60) NULL - , value_test BIGINT IDENTITY (202202081842, 100 ) NOT NULL + , test_scenario CHAR(60) NOT NULL -- Used for unique index + , value_test BIGINT IDENTITY (202202081842, 100 ) NOT NULL -- Used for unique index , inserted_dt DATETIME DEFAULT GETDATE() - , user_login CHAR(255) DEFAULT CURRENT_USER + , user_login CHAR(255) DEFAULT CURRENT_USER NOT NULL -- Used for unique index ) GO CREATE UNIQUE NONCLUSTERED INDEX dbo_tidentityintbigmulti_value_test ON dbo.tidentityintbigmulti (user_login ASC, value_test ASC, test_scenario ASC); 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_TABLES-vu-verify.out b/test/JDBC/expected/BABEL-SP_TABLES-vu-verify.out index 4055ef37c8..2d36807b26 100644 --- a/test/JDBC/expected/BABEL-SP_TABLES-vu-verify.out +++ b/test/JDBC/expected/BABEL-SP_TABLES-vu-verify.out @@ -50,33 +50,37 @@ babel_sp_tables_vu_prepare_db1#!#dbo#!#babel_sp_tables_vu_prepare_mytable2#!#TAB ~~END~~ --- Delimiter table tests NOTE: These to do not produce correct output due to BABEL-2883 +-- Delimiter table tests exec sp_tables @TABLE_NAME = [babel_sp_tables_vu_prepare_mytable1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_tables_vu_prepare_mytable1" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_tables_vu_prepare_db1#!#dbo#!#babel_sp_tables_vu_prepare_mytable1#!#TABLE#!# +~~END~~ exec sp_tables @TABLE_NAME = [babel_sp_tables_vu_prepare_MYTABLE1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_tables_vu_prepare_mytable1" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_tables_vu_prepare_db1#!#dbo#!#babel_sp_tables_vu_prepare_mytable1#!#TABLE#!# +~~END~~ exec sp_tables @TABLE_NAME = [babel_sp_tables_vu_prepare_mytable2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_tables_vu_prepare_mytable2" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_tables_vu_prepare_db1#!#dbo#!#babel_sp_tables_vu_prepare_mytable2#!#TABLE#!# +~~END~~ exec sp_tables @TABLE_NAME = [babel_sp_tables_vu_prepare_MYTABLE2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_tables_vu_prepare_mytable2" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_tables_vu_prepare_db1#!#dbo#!#babel_sp_tables_vu_prepare_mytable2#!#TABLE#!# +~~END~~ -- should only get table within current database diff --git a/test/JDBC/expected/BABEL-SP_TABLES.out b/test/JDBC/expected/BABEL-SP_TABLES.out index d590ac8320..6764fed04c 100644 --- a/test/JDBC/expected/BABEL-SP_TABLES.out +++ b/test/JDBC/expected/BABEL-SP_TABLES.out @@ -68,33 +68,37 @@ db1#!#dbo#!#mytable2#!#TABLE#!# ~~END~~ --- Delimiter table tests NOTE: These to do not produce correct output due to BABEL-2883 +-- Delimiter table tests exec sp_tables @TABLE_NAME = [mytable1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable1" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable1#!#TABLE#!# +~~END~~ exec sp_tables @TABLE_NAME = [MYTABLE1] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable1" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable1#!#TABLE#!# +~~END~~ exec sp_tables @TABLE_NAME = [mytable2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable2" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable2#!#TABLE#!# +~~END~~ exec sp_tables @TABLE_NAME = [MYTABLE2] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable2" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable2#!#TABLE#!# +~~END~~ -- should only get table within current database diff --git a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out index f06b1e417f..5f13195674 100644 --- a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out +++ b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILEGES.out @@ -166,33 +166,53 @@ db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#UPDATE#!#YES ~~END~~ --- Delimiter table tests NOTE: These to do not produce correct output due to BABEL-2883 +-- Delimiter table tests exec sp_table_privileges @TABLE_NAME = [mytable5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_table_privileges @TABLE_NAME = [MYTABLE5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable5#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_table_privileges @TABLE_NAME = [mytable6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_table_privileges @TABLE_NAME = [MYTABLE6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#DELETE#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#INSERT#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#REFERENCES#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#SELECT#!#YES +db1#!#dbo#!#mytable6#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ -- tests fUsePattern = 0 @@ -243,6 +263,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 +280,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 +292,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..fe4dcd734e 100644 --- a/test/JDBC/expected/BABEL-SP_TABLE_PRIVILIGES-vu-verify.out +++ b/test/JDBC/expected/BABEL-SP_TABLE_PRIVILIGES-vu-verify.out @@ -146,33 +146,53 @@ babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_pr ~~END~~ --- Delimiter table tests NOTE: These to do not produce correct output due to BABEL-2883 +-- Delimiter table tests exec sp_table_privileges @TABLE_NAME = [babel_sp_table_priviliges_vu_prepare_mytable5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_table_priviliges_vu_prepare_mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_table_privileges @TABLE_NAME = [babel_sp_table_priviliges_vu_prepare_MYTABLE5] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_table_priviliges_vu_prepare_mytable5" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable5#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_table_privileges @TABLE_NAME = [babel_sp_table_priviliges_vu_prepare_mytable6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_table_priviliges_vu_prepare_mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ exec sp_table_privileges @TABLE_NAME = [babel_sp_table_priviliges_vu_prepare_MYTABLE6] go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: column "babel_sp_table_priviliges_vu_prepare_mytable6" does not exist)~~ +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#DELETE#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#INSERT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#REFERENCES#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#SELECT#!#YES +babel_sp_table_priviliges_vu_prepare_db1#!#dbo#!#babel_sp_table_priviliges_vu_prepare_mytable6#!#dbo#!#dbo#!#UPDATE#!#YES +~~END~~ -- tests fUsePattern = 0 @@ -223,6 +243,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 +260,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 +272,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/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/BABEL-UNSUPPORTED.out b/test/JDBC/expected/BABEL-UNSUPPORTED.out index fa731230d3..9e2a4b6a06 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 @@ -716,9 +707,15 @@ strict - -- escape hatch: fulltext -- 'strict' is default +CREATE DATABASE db_unsupported_ft WITH DEFAULT_FULLTEXT_LANGUAGE = English; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'DEFAULT_FULLTEXT_LANGUAGE' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_fulltext to ignore)~~ + + CREATE TABLE t_unsupported_ft (a text); GO @@ -732,13 +729,6 @@ GO DROP TABLE t_unsupported_ft; GO -CREATE DATABASE db_unsupported_ft WITH DEFAULT_FULLTEXT_LANGUAGE = English; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'DEFAULT_FULLTEXT_LANGUAGE' is not currently supported in Babelfish. please use babelfishpg_tsql.escape_hatch_fulltext to ignore)~~ - - SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') GO ~~START~~ @@ -747,18 +737,46 @@ ignore ~~END~~ -CREATE TABLE t_unsupported_ft (a text); +CREATE DATABASE db_unsupported_ft WITH DEFAULT_FULLTEXT_LANGUAGE = English; GO -CREATE FULLTEXT INDEX ON t_unsupported_ft(a) KEY INDEX ix_unsupported_ft; +DROP DATABASE db_unsupported_ft; GO -DROP TABLE t_unsupported_ft; +CREATE SCHEMA t_unsupported_s_ft; GO -CREATE DATABASE db_unsupported_ft WITH DEFAULT_FULLTEXT_LANGUAGE = English; +CREATE TABLE t_unsupported_s_ft.t_unsupported_ft1 (id int not null, a text); GO -DROP DATABASE db_unsupported_ft; + +CREATE UNIQUE INDEX ix_unsupported_ft1 ON t_unsupported_s_ft.t_unsupported_ft1(id); +GO + +CREATE FULLTEXT INDEX ON t_unsupported_s_ft.t_unsupported_ft1(a) KEY INDEX ix_unsupported_ft1; +GO + +DROP FULLTEXT INDEX ON t_unsupported_s_ft.t_unsupported_ft1; +GO + +DROP TABLE t_unsupported_s_ft.t_unsupported_ft1; +GO + +DROP SCHEMA t_unsupported_s_ft; +GO + +CREATE TABLE t_unsupported_ft2 (id int not null, a text); +GO + +CREATE UNIQUE INDEX ix_unsupported_ft2 ON t_unsupported_ft2(id); +GO + +CREATE FULLTEXT INDEX ON t_unsupported_ft2(a) KEY INDEX ix_unsupported_ft2; +GO + +DROP FULLTEXT INDEX ON t_unsupported_ft2; +GO + +DROP TABLE t_unsupported_ft2; GO SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') @@ -2009,7 +2027,7 @@ babelfishpg_tsql.escape_hatch_checkpoint#!#ignore#!#escape hatch for CHECKPOINT babelfishpg_tsql.escape_hatch_constraint_name_for_default#!#ignore#!#escape hatch for DEFAULT option in alter table add constraint babelfishpg_tsql.escape_hatch_database_misc_options#!#ignore#!#escape hatch for misc options in CREATE/ALTER DATABASE babelfishpg_tsql.escape_hatch_for_replication#!#strict#!#escape hatch for (NOT) FOR REPLICATION option -babelfishpg_tsql.escape_hatch_fulltext#!#strict#!#escape hatch for fulltext +babelfishpg_tsql.escape_hatch_fulltext#!#strict#!#escape hatch for fulltext search babelfishpg_tsql.escape_hatch_ignore_dup_key#!#strict#!#escape hatch for ignore_dup_key=on option in CREATE/ALTER TABLE/INDEX babelfishpg_tsql.escape_hatch_index_clustering#!#ignore#!#escape hatch for CLUSTERED option in CREATE INDEX babelfishpg_tsql.escape_hatch_index_columnstore#!#strict#!#escape hatch for COLUMNSTORE option in CREATE INDEX @@ -2030,6 +2048,7 @@ babelfishpg_tsql.escape_hatch_schemabinding_procedure#!#ignore#!#escape hatch fo babelfishpg_tsql.escape_hatch_schemabinding_trigger#!#ignore#!#escape hatch for SCHEMABINDING option in CREATE TRIGGER babelfishpg_tsql.escape_hatch_schemabinding_view#!#ignore#!#escape hatch for SCHEMABINDING option in CREATE VIEW babelfishpg_tsql.escape_hatch_session_settings#!#strict#!#escape hatch for session settings +babelfishpg_tsql.escape_hatch_set_transaction_isolation_level#!#strict#!#escape hatch for SET TRANSACTION ISOLATION LEVEL babelfishpg_tsql.escape_hatch_showplan_all#!#strict#!#escape hatch for SHOWPLAN_ALL and STATISTICS PROFILE babelfishpg_tsql.escape_hatch_storage_on_partition#!#strict#!#escape hatch for storage_on_partition option in CREATE/ALTER TABLE and CREATE INDEX babelfishpg_tsql.escape_hatch_storage_options#!#ignore#!#escape hatch for storage options option in CREATE/ALTER TABLE/INDEX @@ -2043,6 +2062,8 @@ babelfishpg_tsql.explain_summary#!#on#!#Include summary information (e.g., total babelfishpg_tsql.explain_timing#!#on#!#Include actual startup time and time spent in each node in the output babelfishpg_tsql.explain_verbose#!#off#!#Display additional information regarding the plan babelfishpg_tsql.explain_wal#!#off#!#Include information on WAL record generation +babelfishpg_tsql.isolation_level_repeatable_read#!#off#!#Select mapping for isolation level reapeatable read +babelfishpg_tsql.isolation_level_serializable#!#off#!#Select mapping for isolation level serializable ~~END~~ @@ -2074,7 +2095,7 @@ babelfishpg_tsql.escape_hatch_checkpoint#!#ignore#!#escape hatch for CHECKPOINT babelfishpg_tsql.escape_hatch_constraint_name_for_default#!#ignore#!#escape hatch for DEFAULT option in alter table add constraint babelfishpg_tsql.escape_hatch_database_misc_options#!#ignore#!#escape hatch for misc options in CREATE/ALTER DATABASE babelfishpg_tsql.escape_hatch_for_replication#!#strict#!#escape hatch for (NOT) FOR REPLICATION option -babelfishpg_tsql.escape_hatch_fulltext#!#strict#!#escape hatch for fulltext +babelfishpg_tsql.escape_hatch_fulltext#!#strict#!#escape hatch for fulltext search babelfishpg_tsql.escape_hatch_ignore_dup_key#!#strict#!#escape hatch for ignore_dup_key=on option in CREATE/ALTER TABLE/INDEX babelfishpg_tsql.escape_hatch_index_clustering#!#ignore#!#escape hatch for CLUSTERED option in CREATE INDEX babelfishpg_tsql.escape_hatch_index_columnstore#!#strict#!#escape hatch for COLUMNSTORE option in CREATE INDEX @@ -2095,6 +2116,7 @@ babelfishpg_tsql.escape_hatch_schemabinding_procedure#!#ignore#!#escape hatch fo babelfishpg_tsql.escape_hatch_schemabinding_trigger#!#ignore#!#escape hatch for SCHEMABINDING option in CREATE TRIGGER babelfishpg_tsql.escape_hatch_schemabinding_view#!#ignore#!#escape hatch for SCHEMABINDING option in CREATE VIEW babelfishpg_tsql.escape_hatch_session_settings#!#strict#!#escape hatch for session settings +babelfishpg_tsql.escape_hatch_set_transaction_isolation_level#!#strict#!#escape hatch for SET TRANSACTION ISOLATION LEVEL babelfishpg_tsql.escape_hatch_showplan_all#!#strict#!#escape hatch for SHOWPLAN_ALL and STATISTICS PROFILE babelfishpg_tsql.escape_hatch_storage_on_partition#!#strict#!#escape hatch for storage_on_partition option in CREATE/ALTER TABLE and CREATE INDEX babelfishpg_tsql.escape_hatch_storage_options#!#ignore#!#escape hatch for storage options option in CREATE/ALTER TABLE/INDEX @@ -2108,6 +2130,8 @@ babelfishpg_tsql.explain_summary#!#on#!#Include summary information (e.g., total babelfishpg_tsql.explain_timing#!#on#!#Include actual startup time and time spent in each node in the output babelfishpg_tsql.explain_verbose#!#off#!#Display additional information regarding the plan babelfishpg_tsql.explain_wal#!#off#!#Include information on WAL record generation +babelfishpg_tsql.isolation_level_repeatable_read#!#off#!#Select mapping for isolation level reapeatable read +babelfishpg_tsql.isolation_level_serializable#!#off#!#Select mapping for isolation level serializable ~~END~~ @@ -2120,7 +2144,7 @@ babelfishpg_tsql.escape_hatch_checkpoint#!#ignore#!#escape hatch for CHECKPOINT babelfishpg_tsql.escape_hatch_constraint_name_for_default#!#ignore#!#escape hatch for DEFAULT option in alter table add constraint babelfishpg_tsql.escape_hatch_database_misc_options#!#ignore#!#escape hatch for misc options in CREATE/ALTER DATABASE babelfishpg_tsql.escape_hatch_for_replication#!#strict#!#escape hatch for (NOT) FOR REPLICATION option -babelfishpg_tsql.escape_hatch_fulltext#!#strict#!#escape hatch for fulltext +babelfishpg_tsql.escape_hatch_fulltext#!#strict#!#escape hatch for fulltext search babelfishpg_tsql.escape_hatch_ignore_dup_key#!#strict#!#escape hatch for ignore_dup_key=on option in CREATE/ALTER TABLE/INDEX babelfishpg_tsql.escape_hatch_index_clustering#!#ignore#!#escape hatch for CLUSTERED option in CREATE INDEX babelfishpg_tsql.escape_hatch_index_columnstore#!#strict#!#escape hatch for COLUMNSTORE option in CREATE INDEX @@ -2141,6 +2165,7 @@ babelfishpg_tsql.escape_hatch_schemabinding_procedure#!#ignore#!#escape hatch fo babelfishpg_tsql.escape_hatch_schemabinding_trigger#!#ignore#!#escape hatch for SCHEMABINDING option in CREATE TRIGGER babelfishpg_tsql.escape_hatch_schemabinding_view#!#ignore#!#escape hatch for SCHEMABINDING option in CREATE VIEW babelfishpg_tsql.escape_hatch_session_settings#!#strict#!#escape hatch for session settings +babelfishpg_tsql.escape_hatch_set_transaction_isolation_level#!#strict#!#escape hatch for SET TRANSACTION ISOLATION LEVEL babelfishpg_tsql.escape_hatch_showplan_all#!#strict#!#escape hatch for SHOWPLAN_ALL and STATISTICS PROFILE babelfishpg_tsql.escape_hatch_storage_on_partition#!#strict#!#escape hatch for storage_on_partition option in CREATE/ALTER TABLE and CREATE INDEX babelfishpg_tsql.escape_hatch_storage_options#!#ignore#!#escape hatch for storage options option in CREATE/ALTER TABLE/INDEX @@ -2154,6 +2179,8 @@ babelfishpg_tsql.explain_summary#!#on#!#Include summary information (e.g., total babelfishpg_tsql.explain_timing#!#on#!#Include actual startup time and time spent in each node in the output babelfishpg_tsql.explain_verbose#!#off#!#Display additional information regarding the plan babelfishpg_tsql.explain_wal#!#off#!#Include information on WAL record generation +babelfishpg_tsql.isolation_level_repeatable_read#!#off#!#Select mapping for isolation level reapeatable read +babelfishpg_tsql.isolation_level_serializable#!#off#!#Select mapping for isolation level serializable ~~END~~ @@ -2375,15 +2402,7 @@ ALTER AUTHORIZATION ON a1 TO SCHEMA OWNER; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'ALTER AUTHORIZATION ON' is not currently supported in Babelfish)~~ - - --- kill (BABEL-2159) -KILL 1; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'KILL' is not currently supported in Babelfish)~~ +~~ERROR (Message: 'ALTER AUTHORIZATION on object types other than DATABASE::' is not currently supported in Babelfish)~~ -- alter view (BABEL-2017) @@ -2455,29 +2474,6 @@ DROP TABLE t4919; GO --- PIVOT (265, 488) -CREATE TABLE t265 (c1 VARCHAR(50), c2 VARCHAR(50)); -GO -SELECT * FROM (SELECT c1, c2 FROM t265) AS p PIVOT (COUNT(c1) FOR c2 IN (c1)) AS pv; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'PIVOT' is not currently supported in Babelfish)~~ - -DROP TABLE t265; -GO - -CREATE TABLE t488(id text); -GO -SELECT * FROM (SELECT id from t488) p PIVOT( sum(id)FOR id in (["HI"])) s; -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'PIVOT' is not currently supported in Babelfish)~~ - -DROP TABLE t488; -GO - -- CREATE DATBASE COLLATE (448) CREATE DATABASE t448 COLLATE NOT_VALID_COLLATION; @@ -2551,7 +2547,7 @@ DBCC CLONEDATABASE (d12608, d12608_clone); GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'DBCC' is not currently supported in Babelfish)~~ +~~ERROR (Message: DBCC CLONEDATABASE is not currently supported in Babelfish)~~ DROP DATABASE d12608; GO @@ -2684,14 +2680,14 @@ select func1(DEFAULT); GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'DEFAULT' is not currently supported in Babelfish)~~ +~~ERROR (Message: function func1(unknown) does not exist)~~ EXEC proc1 DEFAULT; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: 'DEFAULT' is not currently supported in Babelfish)~~ +~~ERROR (Message: procedure proc1(unknown) does not exist)~~ -- NATIONAL/VARYING (BABEL-2360/2361) diff --git a/test/JDBC/expected/BABEL-USER-vu-cleanup.out b/test/JDBC/expected/BABEL-USER-vu-cleanup.out index abc52ca7dd..0c17026b74 100644 --- a/test/JDBC/expected/BABEL-USER-vu-cleanup.out +++ b/test/JDBC/expected/BABEL-USER-vu-cleanup.out @@ -18,3 +18,9 @@ GO DROP LOGIN babel_user_vu_prepare_test4 GO + +DROP LOGIN babel_user_vu_prepare_test5 +GO + +DROP LOGIN babel_user_vu_prepare_long_login_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +GO diff --git a/test/JDBC/expected/BABEL-USER-vu-prepare.out b/test/JDBC/expected/BABEL-USER-vu-prepare.out index 044e7db930..0bd1b6d37d 100644 --- a/test/JDBC/expected/BABEL-USER-vu-prepare.out +++ b/test/JDBC/expected/BABEL-USER-vu-prepare.out @@ -10,6 +10,12 @@ GO CREATE LOGIN babel_user_vu_prepare_test4 WITH PASSWORD = 'abc'; GO +CREATE LOGIN babel_user_vu_prepare_test5 WITH PASSWORD = 'abc'; +GO + +CREATE LOGIN babel_user_vu_prepare_long_login_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA WITH PASSWORD = 'abc'; +GO + CREATE PROC babel_user_vu_prepare_user_ext_proc AS BEGIN SELECT rolname, login_name, orig_username, database_name, default_schema_name diff --git a/test/JDBC/expected/BABEL-USER-vu-verify.out b/test/JDBC/expected/BABEL-USER-vu-verify.out index 9b207b69f6..fac3e3f2af 100644 --- a/test/JDBC/expected/BABEL-USER-vu-verify.out +++ b/test/JDBC/expected/BABEL-USER-vu-verify.out @@ -1,3 +1,5 @@ +-- tsql + SELECT rolname, login_name, orig_username, database_name, default_schema_name FROM sys.babelfish_authid_user_ext WHERE orig_username IN ('dbo', 'db_owner', 'guest') @@ -8,13 +10,13 @@ GO varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar master_db_owner#!##!#db_owner#!#master#!# master_dbo#!##!#dbo#!#master#!#dbo -master_guest#!##!#guest#!#master#!# +master_guest#!##!#guest#!#master#!#guest msdb_db_owner#!##!#db_owner#!#msdb#!# msdb_dbo#!##!#dbo#!#msdb#!#dbo -msdb_guest#!##!#guest#!#msdb#!# +msdb_guest#!##!#guest#!#msdb#!#guest tempdb_db_owner#!##!#db_owner#!#tempdb#!# tempdb_dbo#!##!#dbo#!#tempdb#!#dbo -tempdb_guest#!##!#guest#!#tempdb#!# +tempdb_guest#!##!#guest#!#tempdb#!#guest ~~END~~ @@ -203,14 +205,85 @@ babel_user_vu_prepare_test3#!#babel_user_vu_prepare_sch ~~END~~ +-- test ALTER USER...WITH LOGIN +-- login login name (65 character length name) +ALTER USER babel_user_vu_prepare_test3 WITH LOGIN = babel_user_vu_prepare_long_login_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; +GO + +ALTER USER babel_user_vu_prepare_test3 WITH LOGIN = babel_user_vu_prepare_test5; +GO + +EXEC babel_user_vu_prepare_user_ext_proc +GO +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar +master_babel_user_vu_prepare_aacb2aa14e22b38c44e8614f1eae6949f8#!#babel_user_vu_prepare_test4#!#babel_user_vu_prepare_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#!#master#!#dbo +master_babel_user_vu_prepare_test1_new#!#babel_user_vu_prepare_test1#!#babel_user_vu_prepare_test1_new#!#master#!#dbo +master_babel_user_vu_prepare_test2#!#babel_user_vu_prepare_test2#!#babel_user_vu_prepare_test2#!#master#!#dbo +master_babel_user_vu_prepare_test3#!#babel_user_vu_prepare_test5#!#babel_user_vu_prepare_test3#!#master#!#babel_user_vu_prepare_sch +~~END~~ + + +EXEC babel_user_vu_prepare_db_principal_proc +GO +~~START~~ +varchar#!#varchar +babel_user_vu_prepare_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA#!#dbo +babel_user_vu_prepare_test1_new#!#dbo +babel_user_vu_prepare_test2#!#dbo +babel_user_vu_prepare_test3#!#babel_user_vu_prepare_sch +~~END~~ + + +-- reset the login password +ALTER LOGIN babel_user_vu_prepare_test5 WITH PASSWORD = 'abc'; +GO + +-- tsql user=babel_user_vu_prepare_test5 password=abc +SELECT CURRENT_USER; +go +~~START~~ +varchar +babel_user_vu_prepare_test3 +~~END~~ + + +-- psql +-- New login is now member of the user after ALTER +SELECT pg_has_role('babel_user_vu_prepare_test5', 'master_babel_user_vu_prepare_test3', 'member') +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql +-- both of the commands below should fail +ALTER USER babel_user_vu_prepare_test3 WITH LOGIN = babel_user_vu_prepare_test1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Existing user already maps to login 'babel_user_vu_prepare_test1' in current database.)~~ + + +ALTER USER babel_user_vu_prepare_test3 WITH LOGIN = jdbc_user; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The login already has an account under a different user name.)~~ + + SELECT rolname FROM pg_roles WHERE rolname LIKE '%babel_user_vu_prepare%' ORDER BY rolname; GO ~~START~~ varchar +babel_user_vu_prepare_long_logief3e68adff43cde8ecb1392da470244f babel_user_vu_prepare_test1 babel_user_vu_prepare_test2 babel_user_vu_prepare_test3 babel_user_vu_prepare_test4 +babel_user_vu_prepare_test5 master_babel_user_vu_prepare_aacb2aa14e22b38c44e8614f1eae6949f8 master_babel_user_vu_prepare_test1_new master_babel_user_vu_prepare_test2 diff --git a/test/JDBC/expected/BABEL-USER.out b/test/JDBC/expected/BABEL-USER.out index 5ccb991143..d22202a7e1 100644 --- a/test/JDBC/expected/BABEL-USER.out +++ b/test/JDBC/expected/BABEL-USER.out @@ -49,18 +49,18 @@ ORDER BY rolname; GO ~~START~~ varchar#!#varchar#!#nvarchar#!#nvarchar#!#nvarchar -db1_guest#!##!#guest#!#db1#!# +db1_guest#!##!#guest#!#db1#!#guest db_owner#!##!#db_owner#!#db1#!# dbo#!##!#dbo#!#db1#!#dbo master_db_owner#!##!#db_owner#!#master#!# master_dbo#!##!#dbo#!#master#!#dbo -master_guest#!##!#guest#!#master#!# +master_guest#!##!#guest#!#master#!#guest msdb_db_owner#!##!#db_owner#!#msdb#!# msdb_dbo#!##!#dbo#!#msdb#!#dbo -msdb_guest#!##!#guest#!#msdb#!# +msdb_guest#!##!#guest#!#msdb#!#guest tempdb_db_owner#!##!#db_owner#!#tempdb#!# tempdb_dbo#!##!#dbo#!#tempdb#!#dbo -tempdb_guest#!##!#guest#!#tempdb#!# +tempdb_guest#!##!#guest#!#tempdb#!#guest ~~END~~ @@ -70,9 +70,12 @@ ORDER BY default_schema_name DESC, name; GO ~~START~~ varchar#!#varchar +guest#!#guest dbo#!#dbo db_owner#!# -guest#!# +INFORMATION_SCHEMA#!# +public#!# +sys#!# ~~END~~ diff --git a/test/JDBC/expected/BABEL-Use_Statement.out b/test/JDBC/expected/BABEL-Use_Statement.out new file mode 100644 index 0000000000..c2f7098a48 --- /dev/null +++ b/test/JDBC/expected/BABEL-Use_Statement.out @@ -0,0 +1,241 @@ +-- Procedures +-- block statement +CREATE PROCEDURE p AS BEGIN + USE db; +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +-- if_statement +CREATE PROCEDURE p AS BEGIN + DECLARE @i INT = 2; + IF (@i = 2) BEGIN + USE db + END +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +-- else statement +CREATE PROCEDURE p AS BEGIN + DECLARE @i INT =2; + IF (@i=2) BEGIN + SELECT 1 + END + ELSE BEGIN + USE db + END +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +-- try-catch block +CREATE PROCEDURE p AS BEGIN + BEGIN TRY + USE db + END TRY + BEGIN CATCH + SELECT 1 + END CATCH +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE PROCEDURE p AS BEGIN + BEGIN TRY + SELECT 1 + END TRY + BEGIN CATCH + USE db + END CATCH +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +-- while loop +CREATE PROCEDURE p AS BEGIN + DECLARE @i INT = 2 + WHILE @i > 0 BEGIN + USE db + SET @i = @i-1 + END +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +-- multiple loops +CREATE PROCEDURE P(@total INT) AS BEGIN + DECLARE @cnt INT = 0 + WHILE @cnt < @total + BEGIN + SELECT 1 + IF @cnt >= 5 + USE db; + BREAK + SELECT 2 + IF (@cnt < 5) + SELECT 3 + SET @cnt = @cnt + 1 + END +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +-- Triggers +CREATE TABLE tb(i INT); +GO + +CREATE TRIGGER t ON tb +FOR INSERT AS BEGIN + USE db; + INSERT INTo t VALUES(1); +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE TRIGGER t ON tb +AFTER DELETE AS + DECLARE @cnt INT = 0 + WHILE @cnt < @total + BEGIN + SELECT 1 + IF @cnt >= 5 + USE db; + BREAK + SELECT 2 + IF (@cnt < 5) + SELECT 3 + SET @cnt = @cnt + 1 + END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +DROP TABLE tb; +GO + +-- Functions +-- sql_clauses is not supported for function of return type func_body_returns_table_clr +CREATE FUNCTION func() RETURNS TABLE AS + USE db; + RETURN (SELECT * FROM babel_execute_as_caller_table) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'USE' at line 4 and character position 1)~~ + + +CREATE FUNCTION func(@i INT) returns @tableVar table(a text not null) AS +BEGIN + USE db; + RETURN +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE FUNCTION func(@c INT) RETURNS INT AS +BEGIN + USE db; + RETURN (SELECT 1) +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE FUNCTION func(@c INT) RETURNS INT AS +BEGIN + DECLARE @cnt INT = 0 + WHILE @cnt < @total + BEGIN + SELECT 1 + IF @cnt >= 5 + USE db; + BREAK + SELECT 2 + IF (@cnt < 5) + SELECT 3 + SET @cnt = @cnt + 1 + END +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE FUNCTION func() RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT + SELECT @ans= SUM(c1) FROM babel_execute_as_caller_table + if(@ans!=1) + USE db; + RETURN @ans +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE FUNCTION func (@v INT) RETURNS INT WITH RETURNS NULL ON NULL INPUT AS +BEGIN + DECLARE @cnt INT = 0 + WHILE @cnt < @total + BEGIN + SELECT 1 + IF @cnt >= 5 + USE db; + BREAK + SELECT 2 + IF (@cnt < 5) + SELECT 3 + SET @cnt = @cnt + 1 + END +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + + +CREATE FUNCTION func (@v INT) RETURNS INT WITH RETURNS NULL ON NULL INPUT +BEGIN + USE db; + RETURN @v+1 +END; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a USE database statement is not allowed in a procedure, function or trigger.)~~ + diff --git a/test/JDBC/expected/BABEL-guest.out b/test/JDBC/expected/BABEL-guest.out index c290070150..fd0f3a52fa 100644 --- a/test/JDBC/expected/BABEL-guest.out +++ b/test/JDBC/expected/BABEL-guest.out @@ -10,7 +10,7 @@ GO CREATE TABLE babel_2571_table1(a int, b int) GO -CREATE LOGIN babel_2571_login1 WITH password='123' +CREATE LOGIN babel_2571_login1 WITH password='12345678' GO CREATE DATABASE babel_2571_db1 diff --git a/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out b/test/JDBC/expected/BABEL-sp_helpdb-vu-verify.out index dbf3f03029..c5203a3785 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#!#120 +babel_sp_helpdb_db#!#120 ~~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#!#120 ~~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#!#120 ~~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#!#120 +~~END~~ + +SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db'); +GO +~~START~~ +varchar#!#smallint +babel_sp_helpdb_db#!#120 +~~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#!#120 +~~END~~ + +SELECT name, compatibility_level FROM sys.babelfish_helpdb('bAbeL_sP_helPdb_Db '); +GO +~~START~~ +varchar#!#smallint +babel_sp_helpdb_db#!#120 +~~END~~ + + diff --git a/test/JDBC/expected/BABEL_1940.out b/test/JDBC/expected/BABEL_1940.out new file mode 100644 index 0000000000..799aa22457 --- /dev/null +++ b/test/JDBC/expected/BABEL_1940.out @@ -0,0 +1,297 @@ + +-- Test is only valid when default server encoding is WIN1252 +SELECT CONVERT(VARCHAR(MAX), 0x123456789) +GO +~~START~~ +varchar +#Eg‰ +~~END~~ + + +SELECT CONVERT(VARCHAR(10), 0x123456789) +GO +~~START~~ +varchar +#Eg‰ +~~END~~ + + +SELECT CONVERT(VARBINARY(10), '#Eg‰') +GO +~~START~~ +varbinary +0123456789 +~~END~~ + + +SELECT CONVERT(VARCHAR(1), 0x99) +GO +~~START~~ +varchar +â„¢ +~~END~~ + + +SELECT CONVERT(VARCHAR(2), 0x999999) +GO +~~START~~ +varchar +™™ +~~END~~ + + +SELECT CONVERT(VARBINARY(1), 'â„¢') +GO +~~START~~ +varbinary +99 +~~END~~ + + +SELECT CAST('â„¢' AS VARBINARY) +GO +~~START~~ +varbinary +99 +~~END~~ + + +SELECT CAST('™™™' AS VARBINARY(2)) +GO +~~START~~ +varbinary +9999 +~~END~~ + + +SELECT CONVERT(VARCHAR(10), 0x80) +GO +~~START~~ +varchar +€ +~~END~~ + + +-- 0x81 does not exist is empty in some encodings +SELECT CONVERT(VARCHAR(10), 0x81) +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Failed to convert from data type varbinary to varchar, character with byte sequence 0x81 in encoding "WIN1252" has no equivalent in encoding "UTF8")~~ + + +SELECT CONVERT(VARCHAR(10), 0x330033) +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Failed to convert from data type varbinary to varchar, invalid byte sequence for encoding "WIN1252": 0x00)~~ + + +SELECT CONVERT(VARBINARY(10), 'ï½³') +GO +~~START~~ +varbinary +3F +~~END~~ + + +SELECT CONVERT(VARBINARY(10), 'パ') +GO +~~START~~ +varbinary +3F3F +~~END~~ + + +SELECT CONVERT(VARBINARY(10), 'A') +GO +~~START~~ +varbinary +41 +~~END~~ + + +SELECT CONVERT(VARBINARY(10), 'ã‚¢') +GO +~~START~~ +varbinary +3F +~~END~~ + + +SELECT CONVERT(VARBINARY(10), 0x81) +GO +~~START~~ +varbinary +81 +~~END~~ + + +SELECT CONVERT(VARBINARY(10), 0x330033) +GO +~~START~~ +varbinary +330033 +~~END~~ + + +DECLARE @key varchar(20) = 'part1' +DECLARE @email varchar(20) = 'part2' +SELECT CONVERT(VARCHAR(10), HASHBYTES('SHA1', @key + LOWER(@email))) +GO +~~START~~ +varchar +æ/fact¢+Ó +~~END~~ + + + +CREATE TABLE babel_1940_t1 (a VARBINARY(9)) +GO + +INSERT INTO babel_1940_t1 VALUES(0x80) +INSERT INTO babel_1940_t1 VALUES(0xaaa) +INSERT INTO babel_1940_t1 VALUES(0x123456789) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_1940_t1 +GO +~~START~~ +varbinary +80 +0AAA +0123456789 +~~END~~ + + +SELECT CONVERT(VARCHAR(9), a) FROM babel_1940_t1 +GO +~~START~~ +varchar +€ +ª +#Eg‰ +~~END~~ + + +SELECT CAST(a as VARCHAR(9)) FROM babel_1940_t1 +GO +~~START~~ +varchar +€ +ª +#Eg‰ +~~END~~ + + +SELECT CAST(a as VARCHAR(10)) FROM babel_1940_t1 +GO +~~START~~ +varchar +€ +ª +#Eg‰ +~~END~~ + + + +CREATE TABLE babel_1940_t2(a varchar(10) collate japanese_cs_as); +GO + +-- only null bytes becomes empty string since we remove trailing nulls +INSERT INTO babel_1940_t2 VALUES (CAST (0x00 AS VARCHAR)) +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_1940_t2 WHERE a = ''; +GO +~~START~~ +varchar + +~~END~~ + + +INSERT INTO babel_1940_t2 VALUES ('a'), ('b'), ('â„¢'), ('Æ€'), ('ä'); +GO +~~ROW COUNT: 5~~ + + +-- Characters with no mapping transform to Ox3F or ? +SELECT CONVERT(VARBINARY(10), a) FROM babel_1940_t2 +GO +~~START~~ +varbinary + +61 +62 +99 +3F +E4 +~~END~~ + + +-- Truncate trailing null bytes +SELECT CAST(CAST(0x616263 as BINARY(128)) as VARCHAR) +GO +~~START~~ +varchar +abc +~~END~~ + + +-- Block intermidiate null byte +SELECT CAST(CAST(0x610063 as BINARY(128)) as VARCHAR) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Failed to convert from data type varbinary to varchar, invalid byte sequence for encoding "WIN1252": 0x00)~~ + + +DROP TABLE babel_1940_t2 +GO + +DROP TABLE babel_1940_t1 +GO + +SELECT CAST(CAST(0x61 AS VARBINARY) AS BINARY(3)) +GO +~~START~~ +binary +610000 +~~END~~ + + +SELECT CAST(CAST(0x61 AS BINARY(3)) AS VARBINARY(2)) +GO +~~START~~ +varbinary +61 +~~END~~ + + +SELECT CAST(CAST(0x6161616161 AS BINARY(3)) AS VARBINARY(2)) +GO +~~START~~ +varbinary +6161 +~~END~~ + + +SELECT CAST(CAST(0x616263646566 AS VARBINARY(5)) AS BINARY(3)) +GO +~~START~~ +binary +616263 +~~END~~ + diff --git a/test/JDBC/expected/BABEL_4012.out b/test/JDBC/expected/BABEL_4012.out new file mode 100644 index 0000000000..902c9527de --- /dev/null +++ b/test/JDBC/expected/BABEL_4012.out @@ -0,0 +1,622 @@ +CREATE SCHEMA BABEL_4012_sch +GO + +CREATE TABLE BABEL_4012_sch.table1(a int, b int); +GO + +INSERT INTO BABEL_4012_sch.table1 VALUES(1,4), (1,5); +GO +~~ROW COUNT: 2~~ + + +-- WITH ALIAS +-- without qouted identifier in alias +-- with schema name in set and update +UPDATE BABEL_4012_sch.table1 SET BABEL_4012_sch.table1.a = 2 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- with schema name in set and not in update +UPDATE table1 SET BABEL_4012_sch.table1.a = 3 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- with schema name in set and alias in update +UPDATE t1 SET BABEL_4012_sch.table1.a = 1 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- with schema name in update and not in set +UPDATE BABEL_4012_sch.table1 SET table1.a = 2 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- without schema in update and set +UPDATE table1 SET table1.a = 3 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- without schema name in set and alias in update +UPDATE t1 SET table1.a = 1 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- using alias in set and schema in update +UPDATE BABEL_4012_sch.table1 SET t1.a = 2 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- using alias in set and without schema in update +UPDATE table1 SET t1.a = 3 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- using alias in set and update +UPDATE t1 SET t1.a = 1 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- using alias in set and update +UPDATE t1 SET t1.a = 2 FROM BABEL_4012_sch.table1 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- WITH ALIAS +-- with qouted identifier in alias +-- with schema name in set and update +UPDATE BABEL_4012_sch.table1 SET BABEL_4012_sch.table1.a = 3 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- with schema name in set and not in update +UPDATE table1 SET BABEL_4012_sch.table1.a = 2 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- with schema name in set and alias in update +UPDATE "_t1 AbC ã‹â‚°â‚¨" SET BABEL_4012_sch.table1.a = 1 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- with schema name in update and not in set +UPDATE BABEL_4012_sch.table1 SET table1.a = 3 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- without schema in update and set +UPDATE table1 SET table1.a = 2 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- without schema name in set and alias in update +UPDATE "_t1 AbC ã‹â‚°â‚¨" SET table1.a = 1 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- using alias in set and schema in update +UPDATE BABEL_4012_sch.table1 SET "_t1 AbC ã‹â‚°â‚¨".a = 3 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- using alias in set and without schema in update +UPDATE table1 SET "_t1 AbC ã‹â‚°â‚¨".a = 2 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- using alias in set and update +UPDATE "_t1 AbC ã‹â‚°â‚¨" SET "_t1 AbC ã‹â‚°â‚¨".a = 1 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- using alias in set and update +UPDATE "_t1 AbC ã‹â‚°â‚¨" SET "_t1 AbC ã‹â‚°â‚¨".a = 2 FROM BABEL_4012_sch.table1 AS "_t1 AbC ã‹â‚°â‚¨" +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + + + + + +-- WITHOUT ALIAS +-- with schema name in set and update +UPDATE BABEL_4012_sch.table1 SET BABEL_4012_sch.table1.a = 3 FROM BABEL_4012_sch.table1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- with schema name in set and not in update +UPDATE table1 SET BABEL_4012_sch.table1.a = 1 FROM BABEL_4012_sch.table1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +1#!#4 +1#!#5 +~~END~~ + + +-- with schema name in update and not in set +UPDATE BABEL_4012_sch.table1 SET table1.a = 2 FROM BABEL_4012_sch.table1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +2#!#4 +2#!#5 +~~END~~ + + +-- without schema in update and set +UPDATE table1 SET table1.a = 3 FROM BABEL_4012_sch.table1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_sch.table1; +GO +~~START~~ +int#!#int +3#!#4 +3#!#5 +~~END~~ + + +-- DEFAULT SCHEMA +CREATE TABLE BABEL_4012_table2(a int, b int); +GO + +INSERT INTO BABEL_4012_table2 VALUES(1,6), (1,7); +GO +~~ROW COUNT: 2~~ + + +-- WITH ALIAS +-- with schema name in set and update +-- error expected +UPDATE dbo.BABEL_4012_table2 SET dbo.BABEL_4012_table2.a = 2 FROM BABEL_4012_table2 AS t1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The objects "master_dbo.babel_4012_table2" and "babel_4012_table2" in the FROM clause have the same exposed names. Use correlation names to distinguish them.)~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- with schema name in set and not in update +UPDATE BABEL_4012_table2 SET dbo.BABEL_4012_table2.a = 3 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +3#!#6 +3#!#7 +~~END~~ + + +-- with schema name in set and alias in update +UPDATE t1 SET dbo.BABEL_4012_table2.a = 1 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- with schema name in update and not in set +-- error expected +UPDATE dbo.BABEL_4012_table2 SET BABEL_4012_table2.a = 2 FROM BABEL_4012_table2 AS t1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The objects "master_dbo.babel_4012_table2" and "babel_4012_table2" in the FROM clause have the same exposed names. Use correlation names to distinguish them.)~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- without schema in update and set +UPDATE BABEL_4012_table2 SET BABEL_4012_table2.a = 3 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +3#!#6 +3#!#7 +~~END~~ + + +-- without schema name in set and alias in update +UPDATE t1 SET BABEL_4012_table2.a = 1 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- using alias in set and schema in update +-- error expected +UPDATE dbo.BABEL_4012_table2 SET t1.a = 2 FROM BABEL_4012_table2 AS t1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The objects "master_dbo.babel_4012_table2" and "babel_4012_table2" in the FROM clause have the same exposed names. Use correlation names to distinguish them.)~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- using alias in set and without schema in update +UPDATE BABEL_4012_table2 SET t1.a = 3 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +3#!#6 +3#!#7 +~~END~~ + + +-- using alias in set and update +UPDATE t1 SET t1.a = 1 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- using alias in set and update +UPDATE t1 SET t1.a = 2 FROM BABEL_4012_table2 AS t1 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM BABEL_4012_table2; +GO +~~START~~ +int#!#int +2#!#6 +2#!#7 +~~END~~ + + + +-- WITHOUT ALIAS +-- with schema name in set and update +UPDATE dbo.BABEL_4012_table2 SET dbo.BABEL_4012_table2.a = 3 FROM dbo.BABEL_4012_table2 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM dbo.BABEL_4012_table2; +GO +~~START~~ +int#!#int +3#!#6 +3#!#7 +~~END~~ + + +-- with schema name in set and not in update +UPDATE BABEL_4012_table2 SET dbo.BABEL_4012_table2.a = 1 FROM dbo.BABEL_4012_table2 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM dbo.BABEL_4012_table2; +GO +~~START~~ +int#!#int +1#!#6 +1#!#7 +~~END~~ + + +-- with schema name in update and not in set +UPDATE dbo.BABEL_4012_table2 SET BABEL_4012_table2.a = 2 FROM dbo.BABEL_4012_table2 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM dbo.BABEL_4012_table2; +GO +~~START~~ +int#!#int +2#!#6 +2#!#7 +~~END~~ + + +-- without schema in update and set +UPDATE BABEL_4012_table2 SET BABEL_4012_table2.a = 3 FROM dbo.BABEL_4012_table2 +GO +~~ROW COUNT: 2~~ + + +SELECT * FROM dbo.BABEL_4012_table2; +GO +~~START~~ +int#!#int +3#!#6 +3#!#7 +~~END~~ + + + + +-- CLEAR +DROP TABLE BABEL_4012_table2; +GO + +DROP TABLE BABEL_4012_sch.table1; +GO + +DROP SCHEMA BABEL_4012_sch; +GO diff --git a/test/JDBC/expected/BABEL_4145.out b/test/JDBC/expected/BABEL_4145.out new file mode 100644 index 0000000000..e52cb738e6 --- /dev/null +++ b/test/JDBC/expected/BABEL_4145.out @@ -0,0 +1,364 @@ +-- tsql +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'off', 'server' +EXEC sp_babelfish_configure 'isolation_level_serializable', 'off', 'server' +GO +-- terminate-tsql-conn + +-- tsql +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +off +~~END~~ + +~~START~~ +text +off +~~END~~ + +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'pg_isolatin' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid value for parameter "babelfishpg_tsql.isolation_level_repeatable_read": "pg_isolatin")~~ + +EXEC sp_babelfish_configure 'isolation_level_serializable', 'of' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid value for parameter "babelfishpg_tsql.isolation_level_serializable": "of")~~ + +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +off +~~END~~ + +~~START~~ +text +off +~~END~~ + +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'oFf' +GO +EXEC sp_babelfish_configure 'isolation_level_serializable', 'OfF' +GO +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +off +~~END~~ + +~~START~~ +text +off +~~END~~ + +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'Pg_ISOLaTiOn' +GO +EXEC sp_babelfish_configure 'isolation_level_serializable', 'pG_isolaTION' +GO +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +pg_isolation +~~END~~ + +~~START~~ +text +pg_isolation +~~END~~ + +-- terminate-tsql-conn + +-- tsql +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +off +~~END~~ + +~~START~~ +text +off +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read uncommitted +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Isolation level ‘REPEATABLE READ’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_repeatable_read’ config option to get PG repeatable read isolation level.)~~ + +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Isolation level ‘SERIALIZABLE’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_serializable’ config option to get PG serializable isolation level.)~~ + +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +-- terminate-tsql-conn + +-- tsql +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'pg_isolation', 'server' +EXEC sp_babelfish_configure 'isolation_level_serializable', 'off', 'server' +GO +-- terminate-tsql-conn + +-- tsql +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +pg_isolation +~~END~~ + +~~START~~ +text +off +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read uncommitted +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Isolation level ‘SERIALIZABLE’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_serializable’ config option to get PG serializable isolation level.)~~ + +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +-- terminate-tsql-conn + +-- tsql +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'off', 'server' +EXEC sp_babelfish_configure 'isolation_level_serializable', 'pg_isolation', 'server' +GO +-- terminate-tsql-conn + +-- tsql +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +off +~~END~~ + +~~START~~ +text +pg_isolation +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read uncommitted +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Isolation level ‘REPEATABLE READ’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_repeatable_read’ config option to get PG repeatable read isolation level.)~~ + +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +serializable +~~END~~ + +-- terminate-tsql-conn + +-- tsql +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'pg_isolation', 'server' +EXEC sp_babelfish_configure 'isolation_level_serializable', 'pg_isolation', 'server' +GO +-- terminate-tsql-conn + +-- tsql +SELECT current_setting('babelfishpg_tsql.isolation_level_repeatable_read'); +SELECT current_setting('babelfishpg_tsql.isolation_level_serializable'); +GO +~~START~~ +text +pg_isolation +~~END~~ + +~~START~~ +text +pg_isolation +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read uncommitted +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +GO +SELECT current_setting('transaction_isolation'); +GO +~~START~~ +text +serializable +~~END~~ + +-- terminate-tsql-conn + +-- tsql +EXEC sp_babelfish_configure 'isolation_level_repeatable_read', 'off', 'server' +EXEC sp_babelfish_configure 'isolation_level_serializable', 'off', 'server' +GO +-- terminate-tsql-conn diff --git a/test/JDBC/expected/BABEL_4320.out b/test/JDBC/expected/BABEL_4320.out new file mode 100644 index 0000000000..1fc8af5c99 --- /dev/null +++ b/test/JDBC/expected/BABEL_4320.out @@ -0,0 +1,142 @@ +-- dummy test to check if schema is being rewritten +IF (EXISTS (select * from information_schema.test)) +BEGIN + SELECT 1 +END; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "information_schema_tsql.test" does not exist)~~ + + +WHILE (select avg(a) from information_schema.test group by b) < 300 +BEGIN + SELECT 1 +END; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "information_schema_tsql.test" does not exist)~~ + + +SELECT +CASE + WHEN (EXISTS (SELECT * FROM INFORMATION_SCHEMA.test)) THEN 'TRUE' + ELSE 'FALSE' +END +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "information_schema_tsql.test" does not exist)~~ + + +-- regular test cases +CREATE TABLE [dbo].[My_Table_4320]( + [My_ID] [varchar](3) NOT NULL, + [My_Column] [varchar](250) NOT NULL +) +go + +IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'My_Table_4320')) +BEGIN + SELECT 'TABLE EXISTS - THIS IS CORRECT' +END +ELSE +BEGIN + SELECT 'TABLE NOT EXISTS - THIS IS WRONG, BECAUSE IT DOES EXIST' +END +GO +~~START~~ +varchar +TABLE EXISTS - THIS IS CORRECT +~~END~~ + + +WHILE (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'My_Table_4320')) +BEGIN + SELECT 'TABLE EXISTS - THIS IS CORRECT'; + break; +END +GO +~~START~~ +varchar +TABLE EXISTS - THIS IS CORRECT +~~END~~ + + +IF (NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'My_Table_4320')) +BEGIN + SELECT 'TABLE NOT EXISTS - THIS IS WRONG, BECAUSE IT DOES EXIST' +END +ELSE +BEGIN + SELECT 'TABLE EXISTS - THIS IS CORRECT' +END +GO +~~START~~ +varchar +TABLE EXISTS - THIS IS CORRECT +~~END~~ + + +SELECT +CASE + WHEN (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'My_Table_43201')) THEN 'TABLE EXISTS' + ELSE 'TABLE DOES NOT EXIST' +END +GO +~~START~~ +text +TABLE DOES NOT EXIST +~~END~~ + + +SELECT CASE + WHEN (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'My_Table_4320') = 1 THEN 'TABLE EXISTS' + ELSE 'TABEL DOES NOT EXIST' +END; +GO +~~START~~ +text +TABLE EXISTS +~~END~~ + + +-- table identifier truncation +CREATE TABLE ncHdbdnjcnkejnjkcnreunjaknsaowlmfkrngvurtkanajhruddhbcmiuqwpalkdmfhcnbxndwue (a int) +go + +IF (NOT EXISTS(select * from ncHdbdnjcnkejnjkcnreunjaknsaowlmfkrngvurtkanajhruddhbcmiuqwpalkdmfhcnbxndwue)) +BEGIN + SELECT 'Expected result' +END +GO +~~START~~ +varchar +Expected result +~~END~~ + + +-- table and column name truncation +CREATE TABLE jakldnhjcDhdeuqpdkancjdtueqjanckdalejnxutuwmxdjajcneiqmalnfenirlenlaplqirncsrju (ncHdbdnjcnkejnjkcnreunjaknsaowlmfkrngvurtkanajhruddhbcmiuqwpalkdmfhcnbxndwue int) +GO + +IF (NOT EXISTS(select ncHdbdnjcnkejnjkcnreunjaknsaowlmfkrngvurtkanajhruddhbcmiuqwpalkdmfhcnbxndwue from jakldnhjcDhdeuqpdkancjdtueqjanckdalejnxutuwmxdjajcneiqmalnfenirlenlaplqirncsrju)) +BEGIN + SELECT 'Expected result' +END +GO +~~START~~ +varchar +Expected result +~~END~~ + + +DROP TABLE jakldnhjcDhdeuqpdkancjdtueqjanckdalejnxutuwmxdjajcneiqmalnfenirlenlaplqirncsrju; +GO + +DROP TABLE ncHdbdnjcnkejnjkcnreunjaknsaowlmfkrngvurtkanajhruddhbcmiuqwpalkdmfhcnbxndwue; +GO + +DROP TABLE [dbo].[My_Table_4320]; +GO diff --git a/test/JDBC/expected/BABEL_4329.out b/test/JDBC/expected/BABEL_4329.out new file mode 100644 index 0000000000..a30c15bb30 --- /dev/null +++ b/test/JDBC/expected/BABEL_4329.out @@ -0,0 +1,34 @@ +-- psql +create table "#babel-4329"(a int) +go + +-- psql +insert into "#babel-4329" values (1) +go +~~ROW COUNT: 1~~ + + +-- psql +create unique index babel_4329_idx on "#babel-4329"(a) +go + +-- psql +select * from "#babel-4329" +go +~~START~~ +int4 +1 +~~END~~ + + +-- psql +truncate table "#babel-4329" +go + +-- psql +alter table "#babel-4329" rename to "#babel-4329-new" +go + +-- psql +drop table "#babel-4329-new" +go diff --git a/test/JDBC/expected/BABEL_4330-vu-prepare.out b/test/JDBC/expected/BABEL_4330-vu-prepare.out new file mode 100644 index 0000000000..185775d5f5 --- /dev/null +++ b/test/JDBC/expected/BABEL_4330-vu-prepare.out @@ -0,0 +1,19 @@ + +CREATE TABLE babel_4330_vu_prepare_t1(a varchar(50) NULL); +GO + +INSERT INTO babel_4330_vu_prepare_t1 VALUES('ababa'); +GO +~~ROW COUNT: 1~~ + + +CREATE VIEW babel_4330_vu_prepare_v1 AS +SELECT replace(a, 'a', 'c') FROM babel_4330_vu_prepare_t1 +GO + +CREATE FUNCTION babel_4330_vu_prepare_f1() returns table as return +SELECT replace(a, 'a', 'c') FROM babel_4330_vu_prepare_t1 +GO + +CREATE PROCEDURE babel_4330_vu_prepare_p1 AS SELECT replace(a, 'a', 'c') FROM babel_4330_vu_prepare_t1 +GO diff --git a/test/JDBC/expected/BABEL_4330-vu-verify.out b/test/JDBC/expected/BABEL_4330-vu-verify.out new file mode 100644 index 0000000000..f800e74998 --- /dev/null +++ b/test/JDBC/expected/BABEL_4330-vu-verify.out @@ -0,0 +1,45 @@ +SELECT replace(a, 'a', 'c') FROM babel_4330_vu_prepare_t1; +go +~~START~~ +text +cbcbc +~~END~~ + + +SELECT * FROM babel_4330_vu_prepare_v1; +go +~~START~~ +text +cbcbc +~~END~~ + + + +SELECT * FROM babel_4330_vu_prepare_f1(); +go +~~START~~ +text +cbcbc +~~END~~ + + +EXEC babel_4330_vu_prepare_p1; +GO +~~START~~ +text +cbcbc +~~END~~ + + + +DROP PROCEDURE babel_4330_vu_prepare_p1; +GO + +DROP FUNCTION babel_4330_vu_prepare_f1; +GO + +DROP VIEW babel_4330_vu_prepare_v1; +GO + +DROP TABLE babel_4330_vu_prepare_t1; +GO diff --git a/test/JDBC/expected/BABEL_4330.out b/test/JDBC/expected/BABEL_4330.out new file mode 100644 index 0000000000..184baaa241 --- /dev/null +++ b/test/JDBC/expected/BABEL_4330.out @@ -0,0 +1,86 @@ + +-- We should be able to use replace function in computed column. +CREATE TABLE babel_4330_t1(a varchar(50) NULL, b as replace(a, '1', '2')); +GO + +INSERT INTO babel_4330_t1 VALUES('13131'); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_4330_t1 +GO +~~START~~ +varchar#!#text +13131#!#23232 +~~END~~ + + +UPDATE babel_4330_t1 SET a = '14141' WHERE a = '13131'; +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_4330_t1 +GO +~~START~~ +varchar#!#text +14141#!#24242 +~~END~~ + + +ALTER TABLE babel_4330_t1 ADD c AS replace(a, '1','5'); +GO + +SELECT * FROM babel_4330_t1 +GO +~~START~~ +varchar#!#text#!#text +14141#!#24242#!#54545 +~~END~~ + + + +CREATE TABLE babel_4330_t2(a varchar(50) NULL, b as replace(a, NULL, '2')); +GO + +INSERT INTO babel_4330_t2 VALUES('13131'); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_4330_t2 +GO +~~START~~ +varchar#!#text +13131#!# +~~END~~ + + +CREATE TABLE babel_4330_t3(a varchar(50) NULL, b as replace(a, '1', NULL)); +GO + +INSERT INTO babel_4330_t3 VALUES('13131'); +GO +~~ROW COUNT: 1~~ + + +SELECT * FROM babel_4330_t3 +GO +~~START~~ +varchar#!#text +13131#!# +~~END~~ + + +DROP TABLE babel_4330_t1; +GO + + +DROP TABLE babel_4330_t2; +GO + + +DROP TABLE babel_4330_t3; +GO + diff --git a/test/JDBC/expected/BABEL_4367.out b/test/JDBC/expected/BABEL_4367.out new file mode 100644 index 0000000000..c4501ba475 --- /dev/null +++ b/test/JDBC/expected/BABEL_4367.out @@ -0,0 +1,389 @@ + + +-- test for dropping multiple objects at once +-- objects should include both existent and non existent +-- try differnet permutation e.x. DROP TABLE table_exist, table_does_not_exist +-- test with IF EXISTS as well +-- ####### TABLES ####### +CREATE TABLE BABEL_4367_1 ( + id INT +) +GO + +DROP TABLE BABEL_4367_1, BABEL_4367_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: table "babel_4367_2" does not exist)~~ + + +DROP TABLE BABEL_4367_1 +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE TABLE BABEL_4367_1 ( + id INT +) +GO + +DROP TABLE IF EXISTS BABEL_4367_1, BABEL_4367_2 +GO +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE TABLE BABEL_4367_1 ( + id INT +) +GO + +DROP TABLE IF EXISTS BABEL_4367_2, BABEL_4367_1 +GO +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE TABLE BABEL_4367_2 ( + id INT +) +GO + +CREATE TABLE BABEL_4367_3 ( + id INT +) +GO + +DROP TABLE BABEL_4367_1, BABEL_4367_2, BABEL_4367_3 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: table "babel_4367_1" does not exist)~~ + +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2','BABEL_4367_3') ORDER BY name ASC +GO +~~START~~ +varchar +babel_4367_2 +babel_4367_3 +~~END~~ + + +DROP TABLE BABEL_4367_2, BABEL_4367_1, BABEL_4367_3 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: table "babel_4367_1" does not exist)~~ + +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2','BABEL_4367_3') ORDER BY name ASC +GO +~~START~~ +varchar +babel_4367_2 +babel_4367_3 +~~END~~ + + +DROP TABLE IF EXISTS BABEL_4367_1, BABEL_4367_2, BABEL_4367_3 +GO +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2','BABEL_4367_3') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE TABLE BABEL_4367_2 ( + id INT +) +GO + +CREATE TABLE BABEL_4367_3 ( + id INT +) +GO + +DROP TABLE IF EXISTS BABEL_4367_2, BABEL_4367_1, BABEL_4367_3 +GO +SELECT name FROM sys.tables WHERE name in ('BABEL_4367_1', 'BABEL_4367_2','BABEL_4367_3') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + + +-- ####### FUNCTIONS ####### +CREATE FUNCTION BABEL_4367_func() +RETURNS BIGINT +AS BEGIN RETURN 10 END +GO + +DROP FUNCTION BABEL_4367_f, BABEL_4367_func +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a function named "babel_4367_f")~~ + + +DROP FUNCTION BABEL_4367_func +GO +SELECT name FROM sys.objects WHERE name = 'BABEL_4367_func' ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE FUNCTION BABEL_4367_func() +RETURNS BIGINT +AS BEGIN RETURN 10 END +GO + +DROP FUNCTION IF EXISTS BABEL_4367_f, BABEL_4367_func +GO +SELECT name FROM sys.objects WHERE name = 'BABEL_4367_func' ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + + +-- ####### VIEWS ####### +CREATE TABLE BABEL_4367_1 ( + id INT +) +INSERT INTO BABEL_4367_1 VALUES (1), (2), (3) +GO +~~ROW COUNT: 3~~ + + +CREATE VIEW BABEL_4367_VIEW_5 AS SELECT * FROM BABEL_4367_1 WHERE id > 1 +GO + +DROP VIEW BABEL_4367_VIEW_5, BABEL_4367_VIEW_2 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: view "babel_4367_view_2" does not exist)~~ + +SELECT name FROM sys.objects WHERE name = 'BABEL_4367_VIEW_5' +GO +~~START~~ +varchar +babel_4367_view_5 +~~END~~ + +DROP VIEW BABEL_4367_VIEW_2, BABEL_4367_VIEW_5 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: view "babel_4367_view_2" does not exist)~~ + +SELECT name FROM sys.objects WHERE name = 'BABEL_4367_VIEW_5' +GO +~~START~~ +varchar +babel_4367_view_5 +~~END~~ + +DROP VIEW BABEL_4367_VIEW_5 +GO +SELECT name FROM sys.objects WHERE name = 'BABEL_4367_VIEW_5' +GO +~~START~~ +varchar +~~END~~ + + +CREATE VIEW BABEL_4367_VIEW_1 AS SELECT * FROM BABEL_4367_1 WHERE id > 1 +GO +CREATE VIEW BABEL_4367_VIEW_2 AS SELECT * FROM BABEL_4367_1 WHERE id <3 +GO + +DROP VIEW BABEL_4367_VIEW_1, BABEL_4367_VIEW_2 +GO +SELECT name FROM sys.objects WHERE name in ('BABEL_4367_VIEW_1', 'BABEL_4367_VIEW_2') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE VIEW BABEL_4367_VIEW_3 AS SELECT * FROM BABEL_4367_1 WHERE id > 1 +GO +CREATE VIEW BABEL_4367_VIEW_4 AS SELECT * FROM BABEL_4367_1 WHERE id <3 +GO + +DROP VIEW IF EXISTS BABEL_4367_VIEW_3, BABEL_4367_VIEW_4 +GO +SELECT name FROM sys.objects WHERE name in ('BABEL_4367_VIEW_3', 'BABEL_4367_VIEW_4') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +CREATE VIEW BABEL_4367_VIEW_6 AS SELECT * FROM BABEL_4367_1 WHERE id <3 +GO + +DROP VIEW IF EXISTS BABEL_4367_VIEW_1, BABEL_4367_VIEW_6 +GO +SELECT name FROM sys.objects WHERE name in ('BABEL_4367_VIEW_1', 'BABEL_4367_VIEW_6') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +-- #### TYPE ##### +CREATE TYPE BABEL_4367_TYPE_1 from datetime +GO + +DROP TYPE BABEL_4367_TYPE_1, BABEL_4367_TYPE_2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ',' at line 1 and character position 27)~~ + +DROP TYPE IF EXISTS BABEL_4367_TYPE_1, BABEL_4367_TYPE_2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near ',' at line 1 and character position 37)~~ + + +DROP TYPE BABEL_4367_TYPE_2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: type "babel_4367_type_2" does not exist)~~ + + +DROP TYPE BABEL_4367_TYPE_1 +GO + +CREATE TYPE BABEL_4367_TYPE_1 from datetime +GO + +DROP TYPE IF EXISTS BABEL_4367_TYPE_1 +GO + +SELECT name FROM sys.types WHERE name in ('BABEL_4367_TYPE_1', 'BABEL_4367_TYPE_2') ORDER BY name ASC +GO +~~START~~ +text +~~END~~ + + +-- #### PROCEDURE ##### +CREATE PROCEDURE BABEL_4367_PROCEDURE_1 +AS +SELECT 'dummyProc' +GO +CREATE PROCEDURE BABEL_4367_PROCEDURE_2 +AS +SELECT 'dummyProc' +GO + +SELECT name FROM sys.procedures WHERE name in ('BABEL_4367_PROCEDURE_1', 'BABEL_4367_PROCEDURE_2') ORDER BY name ASC +GO +~~START~~ +varchar +babel_4367_procedure_1 +babel_4367_procedure_2 +~~END~~ + + +DROP PROCEDURE BABEL_4367_PROCEDURE_1, BABEL_4367_PROCEDURE_3 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "babel_4367_procedure_3")~~ + + +DROP PROCEDURE BABEL_4367_PROCEDURE_3, BABEL_4367_PROCEDURE_1 +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "babel_4367_procedure_3")~~ + + +DROP PROCEDURE IF EXISTS BABEL_4367_PROCEDURE_1, BABEL_4367_PROCEDURE_3 +GO + +DROP PROCEDURE IF EXISTS BABEL_4367_PROCEDURE_3, BABEL_4367_PROCEDURE_2 +GO + +SELECT name FROM sys.procedures WHERE name in ('BABEL_4367_PROCEDURE_1', 'BABEL_4367_PROCEDURE_2') ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + + +-- #### SEQUENCE ##### +CREATE SEQUENCE BABEL_4367_S_1 +GO +CREATE SEQUENCE BABEL_4367_S_2 +GO + +DROP SEQUENCE BABEL_4367_S_1, BABEL_4367_S_3, BABEL_4367_2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: sequence "babel_4367_s_3" does not exist)~~ + +DROP SEQUENCE BABEL_4367_S_4, BABEL_4367_S_1, BABEL_4367_3 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: sequence "babel_4367_s_4" does not exist)~~ + +DROP SEQUENCE BABEL_4367_S_1, BABEL_4367_S_2 +GO + +CREATE SEQUENCE BABEL_4367_S_1 +GO +CREATE SEQUENCE BABEL_4367_S_3 +GO + +DROP SEQUENCE IF EXISTS BABEL_4367_S_1, BABEL_4367_S_2, BABEL_4367_3 +GO + +CREATE SEQUENCE BABEL_4367_S_2 +GO +DROP SEQUENCE IF EXISTS BABEL_4367_S_1, BABEL_4367_S_2, BABEL_4367_S_3 +GO + +SELECT name FROM sys.objects WHERE name IN ('BABEL_4367_S_1', 'BABEL_4367_S_2', 'BABEL_4367_3') +GO +~~START~~ +varchar +~~END~~ + + +-- #### CLEANUP ##### +-- DROP VIEWS FIRST SINCE THEY DEPEND ON TABLE +DROP SEQUENCE IF EXISTS BABEL_4367_S_1, BABEL_4367_2, BABEL_4367_3 +GO +DROP PROCEDURE IF EXISTS BABEL_4367_PROCEDURE_1, BABEL_4367_PROCEDURE_2, BABEL_4367_PROCEDURE_3 +GO +DROP TYPE IF EXISTS BABEL_4367_TYPE_1 +GO +DROP VIEW IF EXISTS BABEL_4367_VIEW_1, BABEL_4367_VIEW_2, BABEL_4367_VIEW_3, BABEL_4367_VIEW_4, BABEL_4367_VIEW_5, BABEL_4367_VIEW_6 +GO +DROP TABLE IF EXISTS BABEL_4367_1, BABEL_4367_2, BABEL_4367_3 +GO +DROP FUNCTION IF EXISTS BABEL_4367_func +GO diff --git a/test/JDBC/expected/BABEL_4367_2.out b/test/JDBC/expected/BABEL_4367_2.out new file mode 100644 index 0000000000..351aa33d9b --- /dev/null +++ b/test/JDBC/expected/BABEL_4367_2.out @@ -0,0 +1,200 @@ + +-- Test for DROP stmt inside transaction blocks +-- check for both rollbacks and commit +CREATE TABLE BABEL_4367_1 ( + id INT +) +GO +CREATE TABLE BABEL_4367_2 ( + id INT +) +GO + +CREATE VIEW BABEL_4367_V_1 AS SELECT 1 +GO +CREATE VIEW BABEL_4367_V_2 AS SELECT 1 +GO + +CREATE FUNCTION BABEL_4367_F1() +RETURNS BIGINT +AS BEGIN RETURN 10 END +GO +CREATE FUNCTION BABEL_4367_F2() +RETURNS BIGINT +AS BEGIN RETURN 10 END +GO + +CREATE TYPE BABEL_4367_T_1 from datetime +GO +CREATE TYPE BABEL_4367_T_2 from datetime +GO + +CREATE PROCEDURE BABEL_4367_P_1 +AS +SELECT 'dummyProc' +GO +CREATE PROCEDURE BABEL_4367_P_2 +AS +SELECT 'dummyProc' +GO + +CREATE SEQUENCE BABEL_4367_S_1 +GO +CREATE SEQUENCE BABEL_4367_S_2 +GO + +-- BEGIN TRANSACTION -- ROLLBACK +BEGIN TRANSACTION +GO + +DROP PROCEDURE BABEL_4367_P_1 +GO +DROP PROCEDURE IF EXISTS BABEL_4367_P_2 +GO + +DROP SEQUENCE BABEL_4367_S_1 +GO +DROP SEQUENCE IF EXISTS BABEL_4367_S_2 +GO + +DROP VIEW BABEL_4367_V_1 +GO +DROP VIEW IF EXISTS BABEL_4367_V_2 +GO + +DROP TABLE BABEL_4367_1 +GO +DROP TABLE IF EXISTS BABEL_4367_2 +GO + +DROP FUNCTION BABEL_4367_F1 +GO +DROP FUNCTION IF EXISTS BABEL_4367_F2 +GO + +DROP TYPE BABEL_4367_T_1 +GO +DROP TYPE IF EXISTS BABEL_4367_T_2 +GO + +SELECT @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +SELECT name FROM sys.objects WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + +SELECT name FROM sys.types WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +text +~~END~~ + + +ROLLBACK +GO + +-- Check if all objects still exists +SELECT name FROM sys.objects WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +varchar +babel_4367_1 +babel_4367_2 +babel_4367_f1 +babel_4367_f2 +babel_4367_p_1 +babel_4367_p_2 +babel_4367_s_1 +babel_4367_s_2 +babel_4367_v_1 +babel_4367_v_2 +~~END~~ + +SELECT name FROM sys.types WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +text +babel_4367_t_1 +babel_4367_t_2 +~~END~~ + + +-- BEGIN TRANSACTION -- COMMIT +BEGIN TRANSACTION +GO + +DROP PROCEDURE BABEL_4367_P_1 +GO +DROP PROCEDURE IF EXISTS BABEL_4367_P_2 +GO + +DROP SEQUENCE BABEL_4367_S_1 +GO +DROP SEQUENCE IF EXISTS BABEL_4367_S_2 +GO + +DROP VIEW BABEL_4367_V_1 +GO +DROP VIEW IF EXISTS BABEL_4367_V_2 +GO + +DROP TABLE BABEL_4367_1 +GO +DROP TABLE IF EXISTS BABEL_4367_2 +GO + +DROP FUNCTION BABEL_4367_F1 +GO +DROP FUNCTION IF EXISTS BABEL_4367_F2 +GO + +DROP TYPE BABEL_4367_T_1 +GO +DROP TYPE IF EXISTS BABEL_4367_T_2 +GO + +SELECT @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +SELECT name FROM sys.objects WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + +SELECT name FROM sys.types WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +text +~~END~~ + + +COMMIT +GO + +-- Check if all objects are dropped +SELECT name FROM sys.objects WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +varchar +~~END~~ + +SELECT name FROM sys.types WHERE name LIKE 'babel_4367_%' ORDER BY name ASC +GO +~~START~~ +text +~~END~~ + diff --git a/test/JDBC/expected/BABEL_4389.out b/test/JDBC/expected/BABEL_4389.out new file mode 100644 index 0000000000..0d623bcaaa --- /dev/null +++ b/test/JDBC/expected/BABEL_4389.out @@ -0,0 +1,42 @@ + +-- Failure of these indicates use of wrong collation +-- when init scan keys +CREATE VIEW BABEL4389V_1 as SELECT 1 +GO +DROP VIEW BABEL4389V_1 +GO + +CREATE VIEW BABEL4389V1 as SELECT 1 +GO +DROP VIEW BABEL4389V1 +GO + +CREATE VIEW BABEL4389V1 as SELECT 1 +GO +sp_rename 'BABEL4389V1', 'BABEL4389V2', 'OBJECT' +GO +DROP VIEW BABEL4389V2 +GO + +SELECT object_name FROM sys.babelfish_view_def WHERE object_name IN ('BABEL4389V_1', 'BABEL4389V1', 'BABEL4389V2') +GO +~~START~~ +varchar +~~END~~ + + +EXEC sys.babelfish_add_domain_mapping_entry 'BABEL4389D_1', 'CollationCheck' +GO +EXEC sys.babelfish_remove_domain_mapping_entry 'BABEL4389D_1' +GO +EXEC sys.babelfish_add_domain_mapping_entry 'BABEL4389D1', 'CollationCheck' +GO +EXEC sys.babelfish_remove_domain_mapping_entry 'BABEL4389D1' +GO + +SELECT * FROM sys.babelfish_domain_mapping WHERE netbios_domain_name IN ('BABEL4389D1', 'BABEL4389D_1') +GO +~~START~~ +varchar#!#varchar +~~END~~ + diff --git a/test/JDBC/expected/BABEL_4411.out b/test/JDBC/expected/BABEL_4411.out new file mode 100644 index 0000000000..1c3ac35f64 --- /dev/null +++ b/test/JDBC/expected/BABEL_4411.out @@ -0,0 +1,559 @@ + +-- Escape hatch disabled +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +EXEC sp_babelfish_configure 'escape_hatch_set_transaction_isolation_level', 'strict' +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET TRANSACTION ISOLATION failed, transaction aborted, set escape hatch 'escape_hatch_set_transaction_isolation_level' to ignore such error)~~ + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET TRANSACTION ISOLATION failed, transaction aborted, set escape hatch 'escape_hatch_set_transaction_isolation_level' to ignore such error)~~ + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +ROLLBACK +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +COMMIT +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +BEGIN TRANSACTION +GO +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +ROLLBACK +GO + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SAVE TRANSACTION sp1 +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET TRANSACTION ISOLATION failed, transaction aborted, set escape hatch 'escape_hatch_set_transaction_isolation_level' to ignore such error)~~ + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +BEGIN TRANSACTION +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +2 +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +COMMIT +GO +COMMIT +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + +~~START~~ +text +repeatable read +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +COMMIT +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + + + + +-- Escape hatch enabled +EXEC sp_babelfish_configure 'escape_hatch_set_transaction_isolation_level', 'ignore' +GO + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +COMMIT +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +1 +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +ROLLBACK +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +SAVE TRANSACTION sp1 +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +GO +COMMIT +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + diff --git a/test/JDBC/expected/BABEL_4411_2.out b/test/JDBC/expected/BABEL_4411_2.out new file mode 100644 index 0000000000..785289e75f --- /dev/null +++ b/test/JDBC/expected/BABEL_4411_2.out @@ -0,0 +1,449 @@ + +-- Check isolation levels inside procedure and functions +-- CREATE PROCEDURES +CREATE PROCEDURE BABEL_4411_P_1 +AS +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO + +CREATE PROCEDURE BABEL_4411_P_2 +AS +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO + +-- PROCEDURES #### ESCAPE HATCH DISABLED +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +EXEC sp_babelfish_configure 'escape_hatch_set_transaction_isolation_level', 'strict' +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +EXEC BABEL_4411_P_1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET TRANSACTION ISOLATION failed, transaction aborted, set escape hatch 'escape_hatch_set_transaction_isolation_level' to ignore such error)~~ + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +EXEC BABEL_4411_P_2 +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +ROLLBACK +GO + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +EXEC BABEL_4411_P_2 +GO +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +ROLLBACK +GO + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO + +EXEC BABEL_4411_P_2 +GO +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +EXEC BABEL_4411_P_1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET TRANSACTION ISOLATION failed, transaction aborted, set escape hatch 'escape_hatch_set_transaction_isolation_level' to ignore such error)~~ + + +-- PROCEDURES #### ESCAPE HATCH ENABLED +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +EXEC sp_babelfish_configure 'escape_hatch_set_transaction_isolation_level', 'ignore' +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +EXEC BABEL_4411_P_1 +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +COMMIT +GO + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +EXEC BABEL_4411_P_2 +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +ROLLBACK +GO + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO +EXEC BABEL_4411_P_2 +GO +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +ROLLBACK +GO + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO + +EXEC BABEL_4411_P_2 +GO +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + +EXEC BABEL_4411_P_1 +GO +~~START~~ +text +read uncommitted +~~END~~ + +~~START~~ +text +read uncommitted +~~END~~ + + +-- CLEANUP PROCEDURES +DROP PROCEDURE IF EXISTS BABEL_4411_P_1, BABEL_4411_P_2 +GO + + +-- CREATE FUNCTIONS +CREATE FUNCTION BABEL_4367_F1() RETURNS varchar(16) AS +BEGIN +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +RETURN CAST(current_setting('transaction_isolation') as varchar(16)) +END +GO + +CREATE FUNCTION BABEL_4367_F2() RETURNS varchar(16) AS +BEGIN +RETURN CAST(current_setting('transaction_isolation') as varchar(16)) +END +GO + + +-- FUNCTIONS #### ESCAPE HATCH DISABLED +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +EXEC sp_babelfish_configure 'escape_hatch_set_transaction_isolation_level', 'strict' +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SELECT BABEL_4367_F1() +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET is not allowed in a non-volatile function)~~ + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SELECT BABEL_4367_F2() +GO +~~START~~ +varchar +read committed +~~END~~ + +COMMIT +GO + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +SELECT BABEL_4367_F2() +GO +~~START~~ +varchar +repeatable read +~~END~~ + +COMMIT +GO + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO + +SELECT BABEL_4367_F2() +GO +~~START~~ +varchar +read uncommitted +~~END~~ + +SELECT BABEL_4367_F1() +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET is not allowed in a non-volatile function)~~ + + +-- FUNCTIONS #### ESCAPE HATCH ENABLED +SET TRANSACTION ISOLATION LEVEL READ COMMITTED +GO +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +EXEC sp_babelfish_configure 'escape_hatch_set_transaction_isolation_level', 'ignore' +GO +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SELECT BABEL_4367_F1() +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET is not allowed in a non-volatile function)~~ + + +SELECT @@trancount +SELECT current_setting('transaction_isolation') +SELECT current_setting('default_transaction_isolation') +GO +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +read committed +~~END~~ + +~~START~~ +text +read committed +~~END~~ + + +BEGIN TRANSACTION +GO +SELECT BABEL_4367_F2() +GO +~~START~~ +varchar +read committed +~~END~~ + +COMMIT +GO + +BEGIN TRANSACTION +GO +SET TRANSACTION ISOLATION LEVEL SNAPSHOT +SELECT BABEL_4367_F2() +GO +~~START~~ +varchar +repeatable read +~~END~~ + +COMMIT +GO + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED +GO + +SELECT BABEL_4367_F2() +GO +~~START~~ +varchar +read uncommitted +~~END~~ + +SELECT BABEL_4367_F1() +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: SET is not allowed in a non-volatile function)~~ + + +-- CLEANUP FUNCTIONS +DROP FUNCTION IF EXISTS BABEL_4367_F1, BABEL_4367_F2 +GO diff --git a/test/JDBC/expected/BABEL_4442.out b/test/JDBC/expected/BABEL_4442.out new file mode 100644 index 0000000000..fc63a02cad --- /dev/null +++ b/test/JDBC/expected/BABEL_4442.out @@ -0,0 +1,184 @@ +CREATE SCHEMA babel_4442_s1 +GO +CREATE SCHEMA babel_4442_s2 +GO + +CREATE TABLE babel_4442_t (id INT) +GO +CREATE TABLE babel_4442_s1.babel_4442_t (id INT) +GO +CREATE TABLE babel_4442_s2.babel_4442_t (id INT) +GO + +INSERT INTO babel_4442_t VALUES (1) +GO +~~ROW COUNT: 1~~ + +INSERT INTO babel_4442_s1.babel_4442_t VALUES (2), (3) +GO +~~ROW COUNT: 2~~ + +INSERT INTO babel_4442_s2.babel_4442_t VALUES (3), (4), (5) +GO +~~ROW COUNT: 3~~ + + +CREATE FUNCTION babel_4442_f() RETURNS INT AS +BEGIN + RETURN (SELECT COUNT(*) FROM babel_4442_t) +END +GO + +CREATE FUNCTION babel_4442_s1.babel_4442_f() RETURNS INT AS +BEGIN + RETURN (SELECT COUNT(*) FROM babel_4442_t) +END +GO + +CREATE FUNCTION babel_4442_s2.babel_4442_f() RETURNS INT AS +BEGIN + RETURN (SELECT COUNT(*) FROM babel_4442_t) +END +GO + +SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = SCHEMA_NAME() and TABLE_NAME = 'babel_4442_t' +GO +~~START~~ +varchar#!#varchar +babel_4442_t#!#BASE TABLE +~~END~~ + + +SELECT babel_4442_f(), * FROM babel_4442_s1.babel_4442_t +GO +~~START~~ +int#!#int +1#!#2 +1#!#3 +~~END~~ + + +SELECT babel_4442_f(), babel_4442_s1.babel_4442_f(), babel_4442_s2.babel_4442_f(), * FROM babel_4442_s1.babel_4442_t +GO +~~START~~ +int#!#int#!#int#!#int +1#!#2#!#3#!#2 +1#!#2#!#3#!#3 +~~END~~ + + +SELECT babel_4442_f(), babel_4442_s1.babel_4442_f(), babel_4442_s2.babel_4442_f(), * FROM babel_4442_t +GO +~~START~~ +int#!#int#!#int#!#int +1#!#2#!#3#!#1 +~~END~~ + + +SELECT babel_4442_f(), current_setting('search_path'), babel_4442_s1.babel_4442_f(), current_setting('search_path'), + babel_4442_s2.babel_4442_f(), 1, current_setting('search_path'), * FROM babel_4442_t +GO +~~START~~ +int#!#text#!#int#!#text#!#int#!#int#!#text#!#int +1#!#master_dbo, "$user", sys, pg_catalog#!#2#!#master_dbo, "$user", sys, pg_catalog#!#3#!#1#!#master_dbo, "$user", sys, pg_catalog#!#1 +~~END~~ + + +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + + +BEGIN TRANSACTION +GO +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + +SELECT babel_4442_s1.babel_4442_f(), babel_4442_s2.babel_4442_f(), * FROM babel_4442_t +GO +~~START~~ +int#!#int#!#int +2#!#3#!#1 +~~END~~ + +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + +SELECT babel_4442_s1.babel_4442_f(), babel_4442_s2.babel_4442_f(), * FROM babel_4442_t +GO +~~START~~ +int#!#int#!#int +2#!#3#!#1 +~~END~~ + +COMMIT +GO + +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + + +BEGIN TRANSACTION +GO +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + +SELECT babel_4442_s1.babel_4442_f(), babel_4442_s2.babel_4442_f(), * FROM babel_4442_t +GO +~~START~~ +int#!#int#!#int +2#!#3#!#1 +~~END~~ + +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + +SELECT babel_4442_s1.babel_4442_f(), babel_4442_s2.babel_4442_f(), * FROM babel_4442_t +GO +~~START~~ +int#!#int#!#int +2#!#3#!#1 +~~END~~ + +ROLLBACK +GO + +SELECT current_setting('search_path') +GO +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + + +DROP TABLE IF EXISTS babel_4442_t, babel_4442_s1.babel_4442_t, babel_4442_s2.babel_4442_t +GO +DROP FUNCTION IF EXISTS babel_4442_f, babel_4442_s1.babel_4442_f, babel_4442_s2.babel_4442_f +GO +DROP SCHEMA babel_4442_s1 +GO +DROP SCHEMA babel_4442_s2 +GO diff --git a/test/JDBC/expected/BABEL_539-vu-cleanup.out b/test/JDBC/expected/BABEL_539-vu-cleanup.out new file mode 100644 index 0000000000..8d6494f60c --- /dev/null +++ b/test/JDBC/expected/BABEL_539-vu-cleanup.out @@ -0,0 +1,5 @@ +DROP PROC IF EXISTS babel_539_prepare_proc; +GO + +DROP TABLE IF EXISTS babel_539OldTable; +GO diff --git a/test/JDBC/expected/BABEL_539-vu-prepare.out b/test/JDBC/expected/BABEL_539-vu-prepare.out new file mode 100644 index 0000000000..03ec765baa --- /dev/null +++ b/test/JDBC/expected/BABEL_539-vu-prepare.out @@ -0,0 +1,12 @@ +CREATE TABLE babel_539OldTable(col1 int , name varchar(20)); +GO + +INSERT INTO babel_539OldTable VALUES (10, 'user1') , (20, 'user2'), (30, 'user3'); +GO +~~ROW COUNT: 3~~ + + +CREATE PROC babel_539_prepare_proc +AS +SELECT col1, name, IDENTITY(int, 1,2) AS id_num INTO babel_539NewTable_proc FROM babel_539OldTable order by col1; +GO diff --git a/test/JDBC/expected/BABEL_539-vu-verify.out b/test/JDBC/expected/BABEL_539-vu-verify.out new file mode 100644 index 0000000000..6fce7ab01d --- /dev/null +++ b/test/JDBC/expected/BABEL_539-vu-verify.out @@ -0,0 +1,461 @@ +EXEC babel_539_prepare_proc +GO + +SELECT id_num, col1, name FROM babel_539NewTable_proc ORDER BY col1; +GO +~~START~~ +int#!#int#!#varchar +1#!#10#!#user1 +3#!#20#!#user2 +5#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS babel_539NewTable_proc; +GO + +DROP TABLE IF EXISTS babel_539NewTable1; +GO + +SELECT col1, IDENTITY(int, 1,1) AS id_num INTO babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1 FROM babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +DROP TABLE IF EXISTS babel_539NewTable1; +GO + +SELECT col1, IDENTITY(int, 1) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1 FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT col1, IDENTITY(int) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT col1, id_num FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int +10#!#1 +20#!#2 +30#!#3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT col1, id_num=IDENTITY(int, 1,100) INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1 FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int +1#!#10 +101#!#20 +201#!#30 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT col1, [id_num]=IDENTITY(int, 1,1) INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1 FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT col1, identity(int, 1,-100) AS [id_num] INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1 FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int +1#!#10 +-99#!#20 +-199#!#30 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT *, identity(int) AS [id_num] INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1, name FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int#!#varchar +1#!#10#!#user1 +2#!#20#!#user2 +3#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +-- Self Join +SELECT IDENTITY(int,1,1) AS id_num, ltable.col1 AS col1, ltable.name AS name INTO #babel_539NewTable1 +FROM babel_539OldTable AS ltable JOIN babel_539OldTable AS rtable ON ltable.col1 <> rtable.col1 ORDER BY ltable.col1; +GO + +SELECT id_num, col1, name FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#int#!#varchar +1#!#10#!#user1 +2#!#10#!#user1 +3#!#20#!#user2 +4#!#20#!#user2 +5#!#30#!#user3 +6#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT IDENTITY(bigint, 9223372036854775807, -1) id_num, col1, name INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1, name FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +bigint#!#int#!#varchar +9223372036854775807#!#10#!#user1 +9223372036854775806#!#20#!#user2 +9223372036854775805#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT IDENTITY(numeric, -9223372036854775806, +1) id_num, col1, name INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1, name FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +bigint#!#int#!#varchar +-9223372036854775806#!#10#!#user1 +-9223372036854775805#!#20#!#user2 +-9223372036854775804#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT IDENTITY(numeric(19,0), 9223372036854775807, -1) id_num, col1, name INTO #babel_539NewTable1 FROM babel_539OldTable; +GO + +SELECT id_num, col1, name FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +bigint#!#int#!#varchar +9223372036854775807#!#10#!#user1 +9223372036854775806#!#20#!#user2 +9223372036854775805#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT IDENTITY(numeric(19,0), 1, 1) as id_num, * into #babel_539NewTable1 from babel_539OldTable where 1=1; +GO + +SELECT col1, name, id_num FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#varchar#!#bigint +10#!#user1#!#1 +20#!#user2#!#2 +30#!#user3#!#3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT col1, IDENTITY(int, 1, 1) AS id_num, name INTO #babel_539NewTable1 FROM babel_539OldTable ORDER BY col1 DESC; +GO + +SELECT col1, name, id_num FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#varchar#!#int +10#!#user1#!#3 +20#!#user2#!#2 +30#!#user3#!#1 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT DISTINCT IDENTITY(int, 1, 1) AS id_num, col1, name INTO #babel_539NewTable1 FROM babel_539OldTable ORDER BY col1; +GO + +SELECT col1, name, id_num FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#varchar#!#int +10#!#user1#!#1 +20#!#user2#!#2 +30#!#user3#!#3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT DISTINCT name, col1, IDENTITY(int, 1, 1) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable ORDER BY name; +GO + +SELECT col1, name, id_num FROM #babel_539NewTable1 ORDER BY name; +GO +~~START~~ +int#!#varchar#!#int +10#!#user1#!#1 +20#!#user2#!#2 +30#!#user3#!#3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT TOP 2 col1, name, IDENTITY(int, 1, 1) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable ORDER BY col1; +GO + +SELECT col1, name, id_num FROM #babel_539NewTable1 ORDER BY col1; +GO +~~START~~ +int#!#varchar#!#int +10#!#user1#!#1 +20#!#user2#!#2 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +SELECT TOP 2 IDENTITY(int, 1, 1) AS id_num, col1 INTO #babel_539NewTable1 FROM babel_539OldTable ORDER BY col1, name; +GO + +SELECT col1, name, id_num FROM #babel_539NewTable1 ORDER BY col1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "name" does not exist)~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +-- Erros cases +SELECT IDENTITY(int, -10, 1+1) id_num, col1, name INTO #babel_539NewTable1 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'identity')~~ + + +SELECT IDENTITY(int, 1, 1-2) id_num, col1, name INTO #babel_539NewTable1 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'identity')~~ + + +-- Non numeric types +SELECT col1, IDENTITY(char, 1,1) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Parameter or variable '' has an invalid data type.)~~ + + +--UDD +CREATE type test_type_id FROM int; +GO + +SELECT col1, IDENTITY(test_type_id, 1,1) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: A user-defined data type for an IDENTITY column is not currently supported)~~ + + +DROP type test_type_id; +GO + +SELECT col1, IDENTITY(int, 1,1,1) AS id_num INTO #babel_539NewTable1 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ",")~~ + + +DROP TABLE IF EXISTS #babel_539NewTable1; +GO + +-- impact to other similar queries and functions +-- normal create table cases +CREATE TABLE babel_539OldTable2 (col1 int NOT NULL, name varchar(20), id_num INT IDENTITY(1, 2)); +GO + +INSERT INTO babel_539OldTable2 VALUES (10, 'user1') , (20, 'user2'), (30, 'user3'); +GO +~~ROW COUNT: 3~~ + + +DROP TABLE IF EXISTS babel_539NewTable2; +GO + +SELECT id_num, col1, name INTO babel_539NewTable2 FROM babel_539OldTable2 ORDER BY col1; +GO + +SELECT id_num, col1, name FROM babel_539NewTable2 ORDER BY col1; +GO +~~START~~ +int#!#int#!#varchar +1#!#10#!#user1 +3#!#20#!#user2 +5#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS babel_539OldTable2; +GO + +DROP TABLE IF EXISTS babel_539NewTable2; +GO + +-- create table as temp table +CREATE TABLE #babel_539NewTable2 (col1 int, name varchar(20), id_num int IDENTITY(-1, 2)); +GO + +INSERT INTO #babel_539NewTable2(col1, name) VALUES (10, 'user1') , (20, 'user2'), (30, 'user3'); +GO +~~ROW COUNT: 3~~ + + +SELECT id_num, col1, name FROM #babel_539NewTable2 ORDER BY col1; +GO +~~START~~ +int#!#int#!#varchar +-1#!#10#!#user1 +1#!#20#!#user2 +3#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable2; +GO + +CREATE TABLE #babel_539NewTable2 (col1 int, name varchar(20) ); +GO + +SELECT col1, name FROM #babel_539NewTable2 ORDER BY col1; +GO +~~START~~ +int#!#varchar +~~END~~ + + +-- try altering table and check other columns, sequence should drop and any constraints also +ALTER TABLE #babel_539NewTable2 ADD id_num int IDENTITY(1, 1); +GO + +INSERT INTO #babel_539NewTable2(col1, name) VALUES (10, 'user1') , (20, 'user2'), (30, 'user3'); +GO +~~ROW COUNT: 3~~ + + +SELECT id_num, col1, name FROM #babel_539NewTable2 ORDER BY col1; +GO +~~START~~ +int#!#int#!#varchar +1#!#10#!#user1 +2#!#20#!#user2 +3#!#30#!#user3 +~~END~~ + + +DROP TABLE IF EXISTS #babel_539NewTable2; +GO + +-- Two identity columns in a query +SELECT col1, IDENTITY(int, 1,1) as id_num, IDENTITY(int, 1,1) as id_num2 INTO babel_539NewTable2 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Attempting to add multiple identity columns to table "babel_539newtable2" using the SELECT INTO statement.)~~ + + +SELECT col1, IDENTITY() AS id_num INTO babel_539NewTable1 FROM babel_539OldTable; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ")")~~ + + +--calling internal function directly +SELECT sys.IDENTITY(23, 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The IDENTITY function can only be used when the SELECT statement has an INTO clause.)~~ + + +SELECT IDENTITY(int, 21); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The IDENTITY function can only be used when the SELECT statement has an INTO clause.)~~ + + +SELECT sys.IDENTITY_INTO_BIGINT(20, 1, 1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: function IDENTITY_INTO_BIGINT does not exist)~~ + diff --git a/test/JDBC/expected/BABEL_COL_NAME-vu-cleanup.out b/test/JDBC/expected/BABEL_COL_NAME-vu-cleanup.out new file mode 100644 index 0000000000..5bcf8b48db --- /dev/null +++ b/test/JDBC/expected/BABEL_COL_NAME-vu-cleanup.out @@ -0,0 +1,36 @@ +USE babel_3172_test_db; +GO + +DROP TABLE IF EXISTS sys_column_name_vu_t_column_name; +GO + +DROP TABLE IF EXISTS sys_col_name_test_schema.test_table; +GO + +DROP SCHEMA IF EXISTS sys_col_name_test_schema; +GO + +USE master; +GO + +DROP DATABASE IF EXISTS babel_3172_test_db; +GO + +-- Drop views +DROP VIEW IF EXISTS col_name_prepare_v1; +DROP VIEW IF EXISTS col_name_prepare_v2; +DROP VIEW IF EXISTS col_name_prepare_v3; +DROP VIEW IF EXISTS col_name_prepare_v4; +GO + +-- Drop procedures +DROP PROCEDURE IF EXISTS col_name_prepare_p1; +DROP PROCEDURE IF EXISTS col_name_prepare_p2; +DROP PROCEDURE IF EXISTS col_name_prepare_p3; +DROP PROCEDURE IF EXISTS col_name_prepare_p4; +GO + +-- Drop functions +DROP FUNCTION IF EXISTS col_name_prepare_f1(); +DROP FUNCTION IF EXISTS col_name_prepare_f2(); +GO diff --git a/test/JDBC/expected/BABEL_COL_NAME-vu-prepare.out b/test/JDBC/expected/BABEL_COL_NAME-vu-prepare.out new file mode 100644 index 0000000000..c2b84328da --- /dev/null +++ b/test/JDBC/expected/BABEL_COL_NAME-vu-prepare.out @@ -0,0 +1,66 @@ +CREATE DATABASE babel_3172_test_db; +GO + +USE babel_3172_test_db; +GO + +CREATE TABLE sys_column_name_vu_t_column_name( + id int, + names char +) +GO + +CREATE SCHEMA sys_col_name_test_schema; +GO + +CREATE TABLE sys_col_name_test_schema.test_table( + firstName varchar(30) +) +GO + +CREATE VIEW col_name_prepare_v1 AS (SELECT COL_NAME(CAST((SELECT OBJECT_ID('sys_column_name_vu_t_column_name')) AS INT), 1)) +GO + +-- Invalid column, should return NULL +CREATE VIEW col_name_prepare_v2 AS (SELECT COL_NAME(CAST((SELECT OBJECT_ID('sys_column_name_vu_t_column_name')) AS INT), 3)) +GO + +-- Invalid table, should return NULL +CREATE VIEW col_name_prepare_v3 AS (SELECT COL_NAME(CAST((SELECT OBJECT_ID('sys_column_name_vu_t_column_name_invalid')) AS INT), 1)) +GO + +-- Invalid column, should return NULL +CREATE VIEW col_name_prepare_v4 AS (SELECT COL_NAME(CAST((SELECT OBJECT_ID('sys_column_name_vu_t_column_name')) AS INT), NULL)) +GO + +-- Invalid table, should return NULL +CREATE PROCEDURE col_name_prepare_p1 AS (SELECT COL_NAME(NULL, 1)); +GO + +-- Invalid column, should return NULL +CREATE PROCEDURE col_name_prepare_p2 AS (SELECT COL_NAME(CAST((SELECT OBJECT_ID('sys_column_name_vu_t_column_name')) AS INT), -1)) +GO + +-- Invalid table, should return NULL +CREATE PROCEDURE col_name_prepare_p3 AS (SELECT COL_NAME(-1, 1)) +GO + +-- Invalid table and column, should return NULL +CREATE PROCEDURE col_name_prepare_p4 AS (SELECT COL_NAME(-1, -1)) +GO + +-- Invalid column, should return NULL +CREATE FUNCTION col_name_prepare_f1() +RETURNS sys.SYSNAME AS +BEGIN +RETURN (SELECT COL_NAME(CAST((SELECT OBJECT_ID('sys_column_name_vu_t_column_name')) AS INT), 'invalid test expression')) +END +GO + +-- Invalid table, should return NULL +CREATE FUNCTION col_name_prepare_f2() +RETURNS sys.SYSNAME AS +BEGIN +RETURN (SELECT COL_NAME('invalid test expression', 1)) +END +GO diff --git a/test/JDBC/expected/BABEL_COL_NAME-vu-verify.out b/test/JDBC/expected/BABEL_COL_NAME-vu-verify.out new file mode 100644 index 0000000000..15f8ae7603 --- /dev/null +++ b/test/JDBC/expected/BABEL_COL_NAME-vu-verify.out @@ -0,0 +1,137 @@ +USE babel_3172_test_db; +GO + +SELECT * FROM col_name_prepare_v1; +GO +~~START~~ +varchar +id +~~END~~ + + +SELECT * FROM col_name_prepare_v2; +GO +~~START~~ +varchar + +~~END~~ + + +SELECT * FROM col_name_prepare_v3; +GO +~~START~~ +varchar + +~~END~~ + + +SELECT * FROM col_name_prepare_v4; +GO +~~START~~ +varchar + +~~END~~ + + +EXEC col_name_prepare_p1; +GO +~~START~~ +varchar + +~~END~~ + + +EXEC col_name_prepare_p2; +GO +~~START~~ +varchar + +~~END~~ + + +EXEC col_name_prepare_p3; +GO +~~START~~ +varchar + +~~END~~ + + +EXEC col_name_prepare_p4; +GO +~~START~~ +varchar + +~~END~~ + + +SELECT col_name_prepare_f1(); +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "invalid test expression")~~ + + +SELECT col_name_prepare_f2(); +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "invalid test expression")~~ + + +SELECT * FROM COL_NAME(NULL, NULL); +GO +~~START~~ +varchar + +~~END~~ + + + +DECLARE @table_id INT = (SELECT OBJECT_ID('sys_col_name_test_schema.test_table')); +SELECT * FROM COL_NAME(@table_id, 1); +GO +~~START~~ +varchar +firstname +~~END~~ + + +SELECT * FROM COL_NAME('0x1A', 3); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "0x1A")~~ + + +SELECT * FROM COL_NAME(7, 'column_name'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "column_name")~~ + + +SELECT * FROM COL_NAME('0x2F', 'another_column'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "0x2F")~~ + + +SELECT * FROM COL_NAME('0xAB', '0x8C'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "0xAB")~~ + + +SELECT * FROM COL_NAME('sample_table', 'some_column'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "sample_table")~~ + diff --git a/test/JDBC/expected/BABEL_GRANT_CONNECT-vu-verify.out b/test/JDBC/expected/BABEL_GRANT_CONNECT-vu-verify.out index 866b3ebf2f..2b72fb8169 100644 --- a/test/JDBC/expected/BABEL_GRANT_CONNECT-vu-verify.out +++ b/test/JDBC/expected/BABEL_GRANT_CONNECT-vu-verify.out @@ -59,6 +59,10 @@ go ~~ERROR (Message: User 'guest' cannot be dropped, it can only be disabled. The user is already disabled in the current database.)~~ +-- reset the login password +alter login grant_connect_abc with password = 'Babel123' +go + -- tsql user=grant_connect_abc password=Babel123 -- should fail because the grant_connect_db1 doesn't have any user. It has guest user but that's disabled. use grant_connect_db1; diff --git a/test/JDBC/expected/BABEL_OBJECT_DEFINITION-vu-verify.out b/test/JDBC/expected/BABEL_OBJECT_DEFINITION-vu-verify.out index b1ba82a881..3ece58968d 100644 --- a/test/JDBC/expected/BABEL_OBJECT_DEFINITION-vu-verify.out +++ b/test/JDBC/expected/BABEL_OBJECT_DEFINITION-vu-verify.out @@ -120,6 +120,10 @@ int ~~END~~ +-- reset the login password +ALTER LOGIN object_definition_login1 WITH PASSWORD = '12345678'; +GO + -- tsql user=object_definition_login1 password=12345678 -- Test dependency of user's permission on object USE object_definition_db; 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..ff2c0a164e 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 @@ -301,6 +267,10 @@ varchar DROP TABLE #babel_object_id_temp_t1; go +-- reset the login password +ALTER LOGIN babel_object_id_login1 WITH PASSWORD = '12345678'; +GO + -- tsql user=babel_object_id_login1 password=12345678 -- test dependency of user's permission on object USE master @@ -635,6 +605,10 @@ GO grant connect to guest GO +-- reset the login password +ALTER LOGIN babel_object_id_login2 WITH PASSWORD = '12345678'; +GO + -- tsql user=babel_object_id_login2 password=12345678 USE babel_object_id_db GO diff --git a/test/JDBC/expected/BABEL_OBJECT_NAME-vu-verify.out b/test/JDBC/expected/BABEL_OBJECT_NAME-vu-verify.out index 63160f6ddf..c026a42d6d 100644 --- a/test/JDBC/expected/BABEL_OBJECT_NAME-vu-verify.out +++ b/test/JDBC/expected/BABEL_OBJECT_NAME-vu-verify.out @@ -215,6 +215,10 @@ GO GRANT SELECT ON babel_object_name_t_pk TO babel_object_name_master_user1; GO +-- reset the login password +ALTER LOGIN babel_object_name_login1 WITH PASSWORD = '12345678'; +GO + -- tsql user=babel_object_name_login1 password=12345678 USE master GO diff --git a/test/JDBC/expected/BABEL_SCHEMATA-vu-verify.out b/test/JDBC/expected/BABEL_SCHEMATA-vu-verify.out index 59bc3577fd..fa75adc376 100644 --- a/test/JDBC/expected/BABEL_SCHEMATA-vu-verify.out +++ b/test/JDBC/expected/BABEL_SCHEMATA-vu-verify.out @@ -27,6 +27,10 @@ master#!#schema_schemata_13#!#dbo#!##!##!# ~~END~~ +-- reset the login password +ALTER LOGIN schemata_login WITH PASSWORD = '123' +GO + -- tsql user=schemata_login password=123 -- Test if user default schema is not dbo schema -- Check if after revoking the usage permission/ownership from user, it is still showing in catalog or not. diff --git a/test/JDBC/expected/Babel_domain_mapping_test-vu-verify.out b/test/JDBC/expected/Babel_domain_mapping_test-vu-verify.out index 73bb2e7de9..cd0c31cbdf 100644 --- a/test/JDBC/expected/Babel_domain_mapping_test-vu-verify.out +++ b/test/JDBC/expected/Babel_domain_mapping_test-vu-verify.out @@ -84,6 +84,10 @@ abc\test#!#WINDOWS_LOGIN +-- reset the login password +alter login [test_login1] with password = '12345678'; +GO + -- tsql user=test_login1 password=12345678 -- test_login1 should not be able to add mapping exec sys.babelfish_add_domain_mapping_entry 'xyz', 'xyz.babel'; @@ -93,6 +97,11 @@ GO ~~ERROR (Message: Current login test_login1 does not have permission to add new domain mapping entry)~~ +-- tsql +-- reset the login password +alter login [test_login_sa] with password = '12345678'; +GO + -- tsql user=test_login_sa password=12345678 -- test_login_sa should be able to add/remove mapping exec sys.babelfish_add_domain_mapping_entry 'xyz', 'xyz.babel'; diff --git a/test/JDBC/expected/FULLTEXT_INDEX-vu-cleanup.out b/test/JDBC/expected/FULLTEXT_INDEX-vu-cleanup.out new file mode 100644 index 0000000000..f5641a5aa1 --- /dev/null +++ b/test/JDBC/expected/FULLTEXT_INDEX-vu-cleanup.out @@ -0,0 +1,172 @@ +-- psql +-- enable CONTAINS +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = on; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql user=testLogin password=abc +USE master; +GO + +-- enable FULLTEXT +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +-- should throw error because login doesn't have sufficient permissions to DROP FULLTEXT INDEX +DROP FULLTEXT INDEX ON fti_table_t1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot drop the full-text index, because it does not exist or you do not have permission)~~ + + +-- tsql user=jdbc_user password=12345678 +-- enable FULLTEXT +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +DROP FULLTEXT INDEX ON fti_table_t1; +GO + +DROP TABLE IF EXISTS fti_table_t1; +GO + +DROP FULLTEXT INDEX ON fti_table_t2; +GO + +DROP TABLE IF EXISTS fti_table_t2; +GO + +DROP FULLTEXT INDEX ON fti_table_t3; +GO + +DROP TABLE IF EXISTS fti_table_t3; +GO + +DROP FULLTEXT INDEX ON fti_table_t4; +GO + +DROP TABLE IF EXISTS fti_table_t4; +GO + +DROP FULLTEXT INDEX ON fti_table_t5; +GO + +DROP TABLE IF EXISTS fti_table_t5; +GO + +DROP FULLTEXT INDEX ON fti_table_t6; +GO + +DROP TABLE IF EXISTS fti_table_t6; +GO + +DROP FULLTEXT INDEX ON fti_table_t7; +GO + +DROP TABLE IF EXISTS fti_table_t7; +GO + +DROP FULLTEXT INDEX ON fti_schema_s1.fti_table_t8; +GO + +DROP TABLE IF EXISTS fti_schema_s1.fti_table_t8; +GO + +DROP SCHEMA IF EXISTS fti_schema_s1; +GO + +DROP FULLTEXT INDEX ON fti_schema_s2.fti_table_t8; +GO + +DROP TABLE IF EXISTS fti_schema_s2.fti_table_t8; +GO + +DROP SCHEMA IF EXISTS fti_schema_s2; +GO + +-- should throw error as there is no index in the table +DROP FULLTEXT INDEX ON fti_table_no_ix; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Table or indexed view "fti_table_no_ix" does not have a full-text index or user does not have permission to perform this action.)~~ + + +DROP TABLE IF EXISTS fti_table_no_ix; +GO + +DROP TABLE IF EXISTS fti_table_unsupported; +GO + +DROP VIEW IF EXISTS fti_prepare_v1; +GO + +DROP PROCEDURE IF EXISTS fti_prepare_p1; +GO + +DROP FUNCTION IF EXISTS fti_prepare_f1; +GO + +DROP TABLE IF EXISTS fti_schema_s3.fti_table_t9; +GO + +DROP SCHEMA IF EXISTS fti_schema_s3; +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) = 'testLogin' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- tsql +DROP LOGIN testLogin; +GO + +-- disable FULLTEXT +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO +~~START~~ +text +strict +~~END~~ + + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = off; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + diff --git a/test/JDBC/expected/FULLTEXT_INDEX-vu-prepare.out b/test/JDBC/expected/FULLTEXT_INDEX-vu-prepare.out new file mode 100644 index 0000000000..10d0ed1fbb --- /dev/null +++ b/test/JDBC/expected/FULLTEXT_INDEX-vu-prepare.out @@ -0,0 +1,218 @@ +-- psql +-- enable CONTAINS +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = on; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql user=jdbc_user password=12345678 +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +CREATE LOGIN testLogin WITH PASSWORD = '123'; +GO + +USE master; +GO + +CREATE SCHEMA fti_schema_s3; +GO + +CREATE TABLE fti_schema_s3.fti_table_t9(id int NOT NULL, a text); +GO + +CREATE UNIQUE INDEX IX_t9_a ON fti_schema_s3.fti_table_t9(id); +GO + +-- tsql user=testLogin password=123 +-- Create new login with insufficient permissions +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +-- should throw error as new login has insufficient permissions to CREATE FULLTEXT INDEX +CREATE FULLTEXT INDEX ON fti_schema_s3.fti_table_t9(a) KEY INDEX IX_t9_a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: A default full-text catalog does not exist in the database or user does not have permission to perform this action)~~ + + +-- tsql user=jdbc_user password=12345678 +-- Reset to super user +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +-- Index creation on different character data type columns +CREATE TABLE fti_table_t1(id int NOT NULL, a text); +GO + +-- should throw syntax error for NULL index name +CREATE FULLTEXT INDEX ON fti_table_t1(a) KEY INDEX NULL; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'NULL' at line 2 and character position 51)~~ + + +-- should throw error for no unique index on the table +CREATE FULLTEXT INDEX ON fti_table_t1(a) KEY INDEX IX_t1_a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: '"ix_t1_a"' is not a valid index to enforce a full-text search key. A full-text search key must be a unique, non-nullable, single-column index which is not offline, is not defined on a non-deterministic or imprecise nonpersisted computed column, does not have a filter, and has maximum size of 900 bytes. Choose another index for the full-text key.)~~ + + +CREATE UNIQUE INDEX IX_t1_a ON fti_table_t1(id); +GO + +CREATE FULLTEXT INDEX ON fti_table_t1(a) KEY INDEX IX_t1_a; +GO + +CREATE TABLE fti_table_t2(id int not null, b char(10)); +GO + +CREATE UNIQUE INDEX IX_t2_b ON fti_table_t2(id); +GO + +CREATE FULLTEXT INDEX ON fti_table_t2(b) KEY INDEX IX_t2_b; +GO + +CREATE TABLE fti_table_t3(id int not null, c varchar(10)); +GO + +CREATE UNIQUE INDEX IX_t3_c ON fti_table_t3(id); +GO + +CREATE FULLTEXT INDEX ON fti_table_t3(c) KEY INDEX IX_t3_c; +GO + +CREATE TABLE fti_table_t4(id int not null, d nvarchar(10)); +GO + +CREATE UNIQUE INDEX IX_t4_d ON fti_table_t4(id); +GO + +CREATE FULLTEXT INDEX ON fti_table_t4(d) KEY INDEX IX_t4_d; +GO + +CREATE TABLE fti_table_t5(id int not null, e nchar(10)); +GO + +CREATE UNIQUE INDEX IX_t5_e ON fti_table_t5(id); +GO + +CREATE FULLTEXT INDEX ON fti_table_t5(e) KEY INDEX IX_t5_e; +GO + +CREATE TABLE fti_table_t6(id int not null, f ntext); +GO + +CREATE UNIQUE INDEX IX_t6_f ON fti_table_t6(id); +GO + +CREATE FULLTEXT INDEX ON fti_table_t6(f) KEY INDEX IX_t6_f; +GO + +CREATE TABLE fti_table_t7(id int not null, a1 text, b1 char(10), c1 varchar(10)); +GO + +CREATE UNIQUE INDEX IX_t7_a1b1c1 ON fti_table_t7(id); +GO + +-- multi column index creation +CREATE FULLTEXT INDEX ON fti_table_t7(a1, b1, c1) KEY INDEX IX_t7_a1b1c1; +GO + +-- checking if the indexes are created correctly +CREATE VIEW fti_prepare_v1 AS (SELECT indexname FROM pg_indexes WHERE tablename='fti_table_t1' AND indexname LIKE 'ft_index%'); +GO + +CREATE PROCEDURE fti_prepare_p1 AS (SELECT indexname FROM pg_indexes WHERE tablename='fti_table_t2' AND indexname LIKE 'ft_index%'); +GO + + +CREATE FUNCTION fti_prepare_f1() +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @indexName NVARCHAR(MAX); + SELECT @indexName= indexname + FROM pg_indexes + WHERE tablename='fti_table_t3' AND indexname LIKE 'ft_index%'; + RETURN @indexName; +END +GO + +-- Creating index in a new schema +CREATE SCHEMA fti_schema_s1; +GO + +CREATE TABLE fti_schema_s1.fti_table_t8(id int not null, a text, b text); +GO + +CREATE UNIQUE INDEX IX_s1_t8_a ON fti_schema_s1.fti_table_t8(id); +GO + +CREATE FULLTEXT INDEX ON fti_schema_s1.fti_table_t8(a) KEY INDEX IX_s1_t8_a; +GO + +CREATE SCHEMA FTI_schema_s2; +GO + +CREATE TABLE FTI_schema_s2.FTI_table_t8(Id int not null, a text, b text); +GO + +CREATE UNIQUE INDEX IX_s2_t8_a ON FTI_schema_s2.FTI_table_t8(Id); +GO + +-- Case for same table name on different schemas +CREATE FULLTEXT INDEX ON FTI_schema_s2.FTI_table_t8(a) KEY INDEX IX_s2_t8_a; +GO + +-- Table for testing dropping non-existent index, should throw error on dropping +CREATE TABLE fti_table_no_ix(id int not null, a text) +GO + +-- Table for testing unsupported options +CREATE TABLE fti_table_unsupported(id int not null, a text) +GO + +CREATE UNIQUE INDEX ix_unsupported_fti ON fti_table_unsupported(id); +GO + +-- disable FULLTEXT +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO +~~START~~ +text +strict +~~END~~ + + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = off; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + diff --git a/test/JDBC/expected/FULLTEXT_INDEX-vu-verify.out b/test/JDBC/expected/FULLTEXT_INDEX-vu-verify.out new file mode 100644 index 0000000000..f023ce14cd --- /dev/null +++ b/test/JDBC/expected/FULLTEXT_INDEX-vu-verify.out @@ -0,0 +1,192 @@ +-- psql +-- enable CONTAINS +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = on; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql user=jdbc_user password=12345678 +-- enable FULLTEXT +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +USE master; +GO + +-- Fetching index details to check if index is created correctly +SELECT * FROM fti_prepare_v1; +GO +~~START~~ +varchar +ft_indexfti_table_t114dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +EXEC fti_prepare_p1; +GO +~~START~~ +varchar +ft_indexfti_table_t214dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +SELECT fti_prepare_f1(); +GO +~~START~~ +nvarchar +ft_indexfti_table_t314dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +SELECT tablename, indexname FROM pg_indexes WHERE tablename='fti_table_t4' AND indexname LIKE 'ft_index%'; +GO +~~START~~ +varchar#!#varchar +fti_table_t4#!#ft_indexfti_table_t414dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +SELECT tablename, indexname FROM pg_indexes WHERE tablename='fti_table_t5' AND indexname LIKE 'ft_index%'; +GO +~~START~~ +varchar#!#varchar +fti_table_t5#!#ft_indexfti_table_t514dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +SELECT tablename, indexname FROM pg_indexes WHERE tablename='fti_table_t6' AND indexname LIKE 'ft_index%'; +GO +~~START~~ +varchar#!#varchar +fti_table_t6#!#ft_indexfti_table_t614dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +SELECT tablename, indexname FROM pg_indexes WHERE tablename='fti_table_t7' AND indexname LIKE 'ft_index%'; +GO +~~START~~ +varchar#!#varchar +fti_table_t7#!#ft_indexfti_table_t714dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +SELECT tablename, indexname FROM pg_indexes WHERE tablename='fti_table_t8' AND indexname LIKE 'ft_index%'; +GO +~~START~~ +varchar#!#varchar +fti_table_t8#!#ft_indexfti_table_t814dc211cf58dcb9fe2047eb8aa8a5bc0 +fti_table_t8#!#ft_indexfti_table_t814dc211cf58dcb9fe2047eb8aa8a5bc0 +~~END~~ + + +-- Creating more than 1 fulltext index in a table, should throw error +CREATE FULLTEXT INDEX ON fti_schema_s1.fti_table_t8(b) KEY INDEX IX_s1_t8_a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: A full-text index for table or indexed view "fti_table_t8" has already been created.)~~ + + +-- Creating index in a non existent table of a schema, should throw error +CREATE FULLTEXT INDEX ON fti_schema_s1.fti_table_t9(a) KEY INDEX IX_s1_t9_a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "fti_table_t9" does not exist)~~ + + +-- Creating index in a table of a non existent schema, should throw error +CREATE FULLTEXT INDEX ON fti_schema_s4.fti_table_t8(a) KEY INDEX IX_s2_t8_a; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: schema "fti_schema_s4" does not exist)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a TYPE COLUMN a) KEY INDEX ix_unsupported_fti; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'TYPE COLUMN' option is not currently supported in Babelfish)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a LANGUAGE 1033) KEY INDEX ix_unsupported_fti; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'LANGUAGE' option is not currently supported in Babelfish)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a STATISTICAL_SEMANTICS) KEY INDEX ix_unsupported_fti; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'STATISTICAL_SEMANTICS' option is not currently supported in Babelfish)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a) KEY INDEX ix_unsupported_fti ON t_unsupported_catalog; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'CATALOG FILEGROUP OPTION' is not currently supported in Babelfish)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a) KEY INDEX ix_unsupported_fti WITH CHANGE_TRACKING OFF; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'WITH OPTION' is not currently supported in Babelfish)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a) KEY INDEX ix_unsupported_fti WITH STOPLIST = SYSTEM; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'WITH OPTION' is not currently supported in Babelfish)~~ + + +-- should throw unsupported error +CREATE FULLTEXT INDEX ON fti_table_unsupported(a) KEY INDEX ix_unsupported_fti WITH SEARCH PROPERTY LIST = DocumentPropertyList; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'WITH OPTION' is not currently supported in Babelfish)~~ + + +-- reset the login password +ALTER LOGIN testLogin WITH PASSWORD = 'abc'; +GO + +-- disable FULLTEXT +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO +~~START~~ +text +strict +~~END~~ + + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = off; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + diff --git a/test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out b/test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out new file mode 100644 index 0000000000..af83d2ea36 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA-vu-cleanup.out @@ -0,0 +1,75 @@ +-- tsql +-- Drop objects +use grant_schema_d1; +go + +drop table grant_schema_s1.grant_schema_t1; +go + +drop table grant_schema_s1.grant_schema_t2; +go + +drop table grant_schema_s1.grant_schema_t3; +go + +drop view grant_schema_s1.grant_schema_v1; +go + +drop view grant_schema_s1.grant_schema_v2; +go + +drop proc grant_schema_s1.grant_schema_p1; +go + +drop proc grant_schema_s1.grant_schema_p2; +go + +drop function grant_schema_s1.grant_schema_f1; +go + +drop function grant_schema_s1.grant_schema_f2; +go + +drop schema grant_schema_s1; +go + +drop table grant_schema_s2.grant_schema_t1; +go + +drop table grant_schema_s2.grant_schema_t2; +go + +drop schema grant_schema_s2; +go + +drop user grant_schema_u1; +go + +use master; +go + +drop database grant_schema_d1; +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) = 'grant_schema_l1' 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~~ + + +-- tsql +drop login grant_schema_l1; +go diff --git a/test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out b/test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out new file mode 100644 index 0000000000..069a323b57 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA-vu-prepare.out @@ -0,0 +1,74 @@ +-- tsql +-- create objects +create database grant_schema_d1; +go + +use grant_schema_d1; +go + +create login grant_schema_l1 with password = '12345678' +go + +create user grant_schema_u1 for login grant_schema_l1; +go + +create schema grant_schema_s1; +go + +create table grant_schema_s1.grant_schema_t1(a int); +go + +create table grant_schema_s1.grant_schema_t2(b int); +go + +create table grant_schema_s1.grant_schema_t3(c int); +go + +create view grant_schema_s1.grant_schema_v1 as select 2; +go + +create view grant_schema_s1.grant_schema_v2 as select 2; +go + +create proc grant_schema_s1.grant_schema_p1 as select 2; +go + +create proc grant_schema_s1.grant_schema_p2 as select 2; +go + +CREATE FUNCTION grant_schema_s1.grant_schema_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +CREATE FUNCTION grant_schema_s1.grant_schema_f2() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +create schema grant_schema_s2; +go + +create table grant_schema_s2.grant_schema_t1(a int); +go + +create table grant_schema_s2.grant_schema_t2(a int); +go + +-- GRANT OBJECT privilege +grant select on grant_schema_s1.grant_schema_t1 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_t3 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_v1 to grant_schema_u1; +go +grant select on grant_schema_s1.grant_schema_v2 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_p1 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_p2 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_f1 to grant_schema_u1; +go +grant execute on grant_schema_s1.grant_schema_f2 to grant_schema_u1; +go +grant select on grant_schema_s2.grant_schema_t1 to grant_schema_u1; +go +grant select on grant_schema_s2.grant_schema_t2 to grant_schema_u1; +go diff --git a/test/JDBC/expected/GRANT_SCHEMA-vu-verify.out b/test/JDBC/expected/GRANT_SCHEMA-vu-verify.out new file mode 100644 index 0000000000..16a45233e2 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA-vu-verify.out @@ -0,0 +1,291 @@ +-- tsql user=grant_schema_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_t2; -- case 1: has no permission +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t2)~~ + + +select * from grant_schema_s1.grant_schema_v1; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p1; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f1(); +go +~~START~~ +int +10 +~~END~~ + + +-- tsql +-- REVOKE OBJECT privilege +use grant_schema_d1; +go +revoke select on grant_schema_s1.grant_schema_t1 from grant_schema_u1; +go +revoke select on grant_schema_s1.grant_schema_v1 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_p1 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_f1 from grant_schema_u1; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has no privileges, should not be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t1)~~ + + +select * from grant_schema_s1.grant_schema_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view grant_schema_v1)~~ + + +exec grant_schema_s1.grant_schema_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure grant_schema_p1)~~ + + +select * from grant_schema_s1.grant_schema_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function grant_schema_f1)~~ + + +-- tsql +-- GRANT SCHEMA privilege +use grant_schema_d1; +go +grant select, execute on schema::grant_schema_s1 to grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t1; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_t2; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_v1; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p1; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f1(); +go +~~START~~ +int +11 +~~END~~ + + +-- User has OBJECT and SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t3; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_v2; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p2; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f2(); +go +~~START~~ +int +11 +~~END~~ + + +-- tsql +-- Case 6: User has SCHEMA privilege, REVOKE OBJECT privilege +use grant_schema_d1; +go +revoke select on grant_schema_s1.grant_schema_t3 from grant_schema_u1; +go +revoke select on grant_schema_s1.grant_schema_v2 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_p2 from grant_schema_u1; +go +revoke execute on grant_schema_s1.grant_schema_f2 from grant_schema_u1; +go + +-- tsql user=grant_schema_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use grant_schema_d1; +go + +select * from grant_schema_s1.grant_schema_t3; +go +~~START~~ +int +~~END~~ + + +select * from grant_schema_s1.grant_schema_v2; +go +~~START~~ +int +2 +~~END~~ + + +exec grant_schema_s1.grant_schema_p2; +go +~~START~~ +int +2 +~~END~~ + + +select * from grant_schema_s1.grant_schema_f2(); +go +~~START~~ +int +11 +~~END~~ + + +-- tsql +-- User has OBJECT privilege, REVOKE OBJECT privilege +-- case 7: User has no privileges, should not be accessible. +use grant_schema_d1; +go +revoke select on grant_schema_s2.grant_schema_t2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t2; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t2)~~ + + +-- tsql +-- User has OBJECT privilege, REVOKE SCHEMA privilege +-- case 8: User has OBJECT privileges, would not be accessible. +use grant_schema_d1; +go +revoke select on schema::grant_schema_s2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t1)~~ + + +-- tsql +-- User has OBJECT privilege, GRANT and REVOKE SCHEMA privilege +-- case 5: User has OBJECT privileges, would not be accessible. +use grant_schema_d1; +go +grant select on schema::grant_schema_s2 to grant_schema_u1; +go + +revoke select on schema::grant_schema_s2 from grant_schema_u1; +go +use master; +go + +-- tsql user=grant_schema_l1 password=12345678 +use grant_schema_d1; +go + +select * from grant_schema_s2.grant_schema_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table grant_schema_t1)~~ + + diff --git a/test/JDBC/expected/GRANT_SCHEMA.out b/test/JDBC/expected/GRANT_SCHEMA.out new file mode 100644 index 0000000000..1891d68597 --- /dev/null +++ b/test/JDBC/expected/GRANT_SCHEMA.out @@ -0,0 +1,631 @@ +-- tsql +-- create objects +create database babel_4344_d1; +go + +use babel_4344_d1; +go + +create login babel_4344_l1 with password = '12345678' +go + +create user babel_4344_u1 for login babel_4344_l1; +go + +create schema babel_4344_s1; +go + +create schema babel_4344_s2 authorization babel_4344_u1; +go + +create table babel_4344_t1(a int); +go + +create table babel_4344_s1.babel_4344_t1(a int); +go + +create table babel_4344_s2.babel_4344_t1(a int); +go + +create table babel_4344_t3(a int, b int); +go + +create table babel_4344_s1.babel_4344_t3(a int, b int); +go + +create view babel_4344_v1 as select 1; +go + +create view babel_4344_s1.babel_4344_v1 as select 2; +go + +create proc babel_4344_p1 as select 1; +go + +create proc babel_4344_s1.babel_4344_p1 as select 2; +go + +CREATE FUNCTION babel_4344_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.tables) END +go + +CREATE FUNCTION babel_4344_s1.babel_4344_f1() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go + +-- tsql user=babel_4344_l1 password=12345678 +use babel_4344_d1; +go + +-- User doesn't have any privileges, objects should not be accessible +select * from babel_4344_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +select * from babel_4344_s1.babel_4344_t1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +insert into babel_4344_s1.babel_4344_t1 values(1); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +select * from babel_4344_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1)~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1)~~ + +exec babel_4344_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1)~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1)~~ + +select * from babel_4344_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1)~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1)~~ + +use master; +go + +-- tsql +-- GRANT OBJECT privilege +use babel_4344_d1; +go +grant select on babel_4344_t1 to babel_4344_u1; +go +grant select on babel_4344_s1.babel_4344_t1 to babel_4344_u1; +go +grant all on babel_4344_s1.babel_4344_t1 to babel_4344_u1; +go +grant select on babel_4344_t3(a) to babel_4344_u1; -- column privilege +go +grant select on babel_4344_s1.babel_4344_t3(a) to babel_4344_u1; -- column privilege +go +grant select on babel_4344_v1 to babel_4344_u1; +go +grant select on babel_4344_s1.babel_4344_v1 to babel_4344_u1; +go +grant execute on babel_4344_p1 to babel_4344_u1; +go +grant execute on babel_4344_s1.babel_4344_p1 to babel_4344_u1; +go +grant execute on babel_4344_f1 to babel_4344_u1; +go +grant execute on babel_4344_s1.babel_4344_f1 to babel_4344_u1; +go +-- Grant schema permission to its owner, should fail +grant select on schema::babel_4344_s2 to babel_4344_u1; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + +grant select on schema::babel_4344_s2 to jdbc_user; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'jdbc_user', because it does not exist or you do not have permission.)~~ + +grant select on schema::babel_4344_s2 to guest; -- should pass +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_t1; +go +~~START~~ +int +~~END~~ + +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(2); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_t3; -- not accessible, only column privilege is granted +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_s1.babel_4344_t3 -- not accessible, only column privilege is granted +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_v1; +go +~~START~~ +int +1 +~~END~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_p1; +go +~~START~~ +int +1 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_f1(); +go +~~START~~ +int +3 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~START~~ +int +9 +~~END~~ + +-- Grant schema permission to its owner +grant select on schema::babel_4344_s2 to babel_4344_u1; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot grant, deny, or revoke permissions to sa, dbo, entity owner, information_schema, sys, or yourself.)~~ + +grant select on schema::babel_4344_s2 to guest; -- should pass +go +grant select on schema::babel_4344_s1 to babel_4344_u1; -- should fail +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the schema "babel_4344_s1", because it does not exist or you do not have permission.)~~ + +use master; +go + +-- tsql +-- GRANT SCHEMA privilege +use babel_4344_d1; +go +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT and SCHEMA privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +2 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(3); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_t3 +go +~~START~~ +int#!#int +~~END~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~START~~ +int +10 +~~END~~ + +use master; +go + +-- tsql +-- REVOKE SCHEMA privilege +use babel_4344_d1; +go +revoke select, insert, execute on schema::babel_4344_s1 from babel_4344_u1; +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has OBJECT privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +2 +3 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(3); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_t3 -- not accessible +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; -- TODO: should be accessible +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); -- TODO: should be accessible +go +~~START~~ +int +9 +~~END~~ + +select * from babel_4344_s2.babel_4344_t1; +go +~~START~~ +int +~~END~~ + +use master; +go + +-- tsql +-- create new objects in same schema +use babel_4344_d1; +go +-- Grant the permissions again +grant select, insert, execute on schema::babel_4344_s1 to babel_4344_u1; +go +create table babel_4344_s1.babel_4344_t2(a int); +go +create view babel_4344_s1.babel_4344_v2 as select 2; +go +create proc babel_4344_s1.babel_4344_p2 as select 2; +go +CREATE FUNCTION babel_4344_s1.babel_4344_f2() RETURNS INT AS BEGIN RETURN (SELECT COUNT(*) FROM sys.objects) END +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has SCHEMA privileges,objects should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t2 +go +~~START~~ +int +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(4); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_v2; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p2; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f2(); +go +~~START~~ +int +14 +~~END~~ + +use master; +go + +-- tsql +-- REVOKE OBJECT privileges +use babel_4344_d1; +go +REVOKE all on babel_4344_s1.babel_4344_t1 FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_t3(a) FROM babel_4344_u1; +go +REVOKE select on babel_4344_s1.babel_4344_v1 FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_p1 FROM babel_4344_u1; +go +REVOKE execute on babel_4344_s1.babel_4344_f1 FROM babel_4344_u1; +go +REVOKE all on babel_4344_s1.babel_4344_f1 FROM babel_4344_u1; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has SCHEMA privileges, should be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1 +go +~~START~~ +int +2 +3 +3 +4 +~~END~~ + +insert into babel_4344_s1.babel_4344_t1 values(5); +go +~~ROW COUNT: 1~~ + +select * from babel_4344_s1.babel_4344_t3; +go +~~START~~ +int#!#int +~~END~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~START~~ +int +2 +~~END~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~START~~ +int +2 +~~END~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~START~~ +int +14 +~~END~~ + +select * from babel_4344_s2.babel_4344_t1; +go +~~START~~ +int +~~END~~ + +use master; +go + +-- tsql +-- REVOKE SCHEMA privileges +use babel_4344_d1; +go +revoke select, insert, execute on schema::babel_4344_s1 from babel_4344_u1; +go +use master; +go + +-- tsql user=babel_4344_l1 password=12345678 +-- User has no privileges, shouldn't be accessible. +use babel_4344_d1; +go +select * from babel_4344_s1.babel_4344_t1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +insert into babel_4344_s1.babel_4344_t1 values(5); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t1)~~ + +select * from babel_4344_s1.babel_4344_t3; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table babel_4344_t3)~~ + +select * from babel_4344_s1.babel_4344_v1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for view babel_4344_v1)~~ + +exec babel_4344_s1.babel_4344_p1; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for procedure babel_4344_p1)~~ + +select * from babel_4344_s1.babel_4344_f1(); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for function babel_4344_f1)~~ + +use master; +go + +-- tsql +-- Drop objects +use babel_4344_d1; +go + +drop table babel_4344_t1; +go + +drop table babel_4344_s1.babel_4344_t1; +go + +drop table babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t3; +go + +drop table babel_4344_s1.babel_4344_t2; +go + +drop view babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v1; +go + +drop view babel_4344_s1.babel_4344_v2; +go + +drop proc babel_4344_p1; +go + +drop proc babel_4344_s1.babel_4344_p1; +go + +drop proc babel_4344_s1.babel_4344_p2; +go + +drop function babel_4344_f1; +go + +drop function babel_4344_s1.babel_4344_f1; +go + +drop function babel_4344_s1.babel_4344_f2; +go + +drop schema babel_4344_s1; +go + +drop table babel_4344_s2.babel_4344_t1; +go + +drop schema babel_4344_s2; +go + +drop user babel_4344_u1; +go + +use master; +go + +drop database babel_4344_d1; +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) = 'babel_4344_l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +go +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +-- tsql +drop login babel_4344_l1; +go diff --git a/test/JDBC/expected/ISC-Check-Constraints-vu-verify.out b/test/JDBC/expected/ISC-Check-Constraints-vu-verify.out index 0e25091475..7e65a122c1 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)', sys.timezone(col1, getutcdate()), 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/expected/ISC-Columns-vu-cleanup.out b/test/JDBC/expected/ISC-Columns-vu-cleanup.out index 12eb4ec818..6b112cb429 100644 --- a/test/JDBC/expected/ISC-Columns-vu-cleanup.out +++ b/test/JDBC/expected/ISC-Columns-vu-cleanup.out @@ -4,6 +4,9 @@ GO DROP VIEW isc_columns_vu_prepare_v1 GO +DROP VIEW isc_columns_bytea_v2 +GO + DROP FUNCTION isc_columns_vu_prepare_f2 DROP FUNCTION isc_columns_vu_prepare_f1 GO @@ -19,4 +22,5 @@ GO DROP TABLE isc_columns_vu_prepare_var DROP TABLE isc_columns_vu_prepare_dates DROP TABLE isc_columns_vu_prepare_nums +DROP TABLE isc_columns_vu_prepare_bytea GO diff --git a/test/JDBC/expected/ISC-Columns-vu-prepare.out b/test/JDBC/expected/ISC-Columns-vu-prepare.out index 89c6051a5d..491ba440ec 100644 --- a/test/JDBC/expected/ISC-Columns-vu-prepare.out +++ b/test/JDBC/expected/ISC-Columns-vu-prepare.out @@ -10,6 +10,10 @@ GO CREATE TABLE isc_columns_vu_prepare_nums(a INT, b SMALLINT, c TINYINT, d BIGINT, e BIT, f FLOAT, g REAL, h NUMERIC(5,3), i MONEY, j SMALLMONEY) GO +-- test bytea datatype +CREATE TABLE isc_columns_vu_prepare_bytea(a bytea, b image) +GO + -- test with different db CREATE DATABASE isc_columns_db1 GO @@ -49,3 +53,8 @@ GO CREATE VIEW isc_columns_vu_prepare_v1 AS SELECT * FROM information_schema.columns WHERE TABLE_NAME LIKE '%isc_columns_UDT%' ORDER BY DATA_TYPE,COLUMN_NAME GO + +-- dep view +CREATE VIEW isc_columns_bytea_v2 AS + SELECT * FROM information_schema.columns WHERE TABLE_NAME = 'isc_columns_vu_prepare_bytea' ORDER BY DATA_TYPE,COLUMN_NAME +GO diff --git a/test/JDBC/expected/ISC-Columns-vu-verify.out b/test/JDBC/expected/ISC-Columns-vu-verify.out index a226123d0a..ada5f86efe 100644 --- a/test/JDBC/expected/ISC-Columns-vu-verify.out +++ b/test/JDBC/expected/ISC-Columns-vu-verify.out @@ -23,15 +23,17 @@ SELECT * FROM information_schema.columns WHERE TABLE_NAME LIKE '%ISC_COLUMNS_VU_ 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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -76,15 +78,17 @@ master#!#dbo#!#isc_columns_vu_prepare_var#!#j#!#10#!##!#YES#!#xml#!#-1#!#- ~~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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -141,20 +145,22 @@ EXEC isc_columns_vu_prepare_p1 GO ~~START~~ int -49 +51 ~~END~~ ~~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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -203,7 +209,7 @@ SELECT * FROM isc_columns_vu_prepare_f2() GO ~~START~~ int -49 +51 ~~END~~ ~~START~~ @@ -221,3 +227,11 @@ master#!#dbo#!#isc_columns_udt#!#b#!#2#!##!#YES#!#varchar#!#10#!#10#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# +~~END~~ + diff --git a/test/JDBC/expected/ISC-Table_Constraints-vu-verify.out b/test/JDBC/expected/ISC-Table_Constraints-vu-verify.out index a3a21ce0ad..0614ed8925 100644 --- a/test/JDBC/expected/ISC-Table_Constraints-vu-verify.out +++ b/test/JDBC/expected/ISC-Table_Constraints-vu-verify.out @@ -121,6 +121,10 @@ int ~~END~~ +-- reset the login password +alter login user_tbl_const with password='123456789'; +go + -- tsql user=user_tbl_const password=123456789 -- should return 0 since user_tbl_const doesn't have any privileges use db1; 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/SYSTEM_USER-vu-verify.out b/test/JDBC/expected/SYSTEM_USER-vu-verify.out index 93916efaf8..465887d182 100644 --- a/test/JDBC/expected/SYSTEM_USER-vu-verify.out +++ b/test/JDBC/expected/SYSTEM_USER-vu-verify.out @@ -7,6 +7,10 @@ dbo#!#jdbc_user#!#dbo#!#master ~~END~~ +-- reset the login password +ALTER LOGIN system_user_vu_prepare_r1 WITH PASSWORD = '123'; +GO + -- tsql user=system_user_vu_prepare_r1 password=123 SELECT session_user, system_user, current_user, db_name(); GO @@ -16,6 +20,11 @@ guest#!#system_user_vu_prepare_r1#!#guest#!#master ~~END~~ +-- tsql +-- reset the login password +ALTER LOGIN system_user_vu_prepare_r2 WITH PASSWORD = '123'; +GO + -- tsql user=system_user_vu_prepare_r2 password=123 SELECT session_user, system_user, current_user, db_name(); GO 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..a3e5275674 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,63 +437,67 @@ 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~~ +-- reset the login password +ALTER LOGIN test_sp_babelfish_volatility_login WITH PASSWORD = '12345678'; +go + -- tsql user=test_sp_babelfish_volatility_login password=12345678 /* function on which user has privilege is only visible */ use test_sp_babelfish_volatility_db1 @@ -558,44 +562,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 +624,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 +644,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~~ @@ -668,6 +672,10 @@ go grant connect to guest go +-- reset the login password +ALTER LOGIN test_sp_babelfish_volatility_login_2 WITH PASSWORD = '12345678' +GO + -- tsql user=test_sp_babelfish_volatility_login_2 password=12345678 use test_sp_babelfish_volatility_db1 go @@ -684,16 +692,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 +714,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/Test-sp_execute_postgresql-susercheck.out b/test/JDBC/expected/Test-sp_execute_postgresql-susercheck.out new file mode 100644 index 0000000000..5ada80e9ec --- /dev/null +++ b/test/JDBC/expected/Test-sp_execute_postgresql-susercheck.out @@ -0,0 +1,47 @@ +-- tsql +-- throw error if login does not have sysadmin privilege(it has only superuser) +create login l3 with password = '12345678' +go + +-- psql +-- grant Superuser +alter user l3 with Superuser; +go + +-- tsql user=l3 password=12345678 +exec sp_execute_postgresql 'create extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied to create extension)~~ + + +-- 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) = 'l3' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + + +-- psql +select pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- psql +-- revoke superuser +ALTER USER l3 with NOSUPERUSER; +go + +-- tsql +drop login l3 +go diff --git a/test/JDBC/expected/Test-sp_execute_postgresql-vu-cleanup.out b/test/JDBC/expected/Test-sp_execute_postgresql-vu-cleanup.out new file mode 100644 index 0000000000..696786d1b8 --- /dev/null +++ b/test/JDBC/expected/Test-sp_execute_postgresql-vu-cleanup.out @@ -0,0 +1,4 @@ +DROP PROC test_sp_execute_postgresql_proc +GO +EXEC sp_execute_postgresql 'DROP EXTENSION fuzzystrmatch;' +GO diff --git a/test/JDBC/expected/Test-sp_execute_postgresql-vu-prepare.out b/test/JDBC/expected/Test-sp_execute_postgresql-vu-prepare.out new file mode 100644 index 0000000000..f268501bb8 --- /dev/null +++ b/test/JDBC/expected/Test-sp_execute_postgresql-vu-prepare.out @@ -0,0 +1,7 @@ +-- procedure dependent on sp_execute_postgresql proc +CREATE PROC test_sp_execute_postgresql_proc +AS +BEGIN + EXEC sp_execute_postgresql 'create extension fuzzystrmatch' +END +go diff --git a/test/JDBC/expected/Test-sp_execute_postgresql-vu-verify.out b/test/JDBC/expected/Test-sp_execute_postgresql-vu-verify.out new file mode 100644 index 0000000000..6b10ceefd8 --- /dev/null +++ b/test/JDBC/expected/Test-sp_execute_postgresql-vu-verify.out @@ -0,0 +1,3 @@ +-- execute the procedure dependent on sp_execute_postgresql proc +EXEC test_sp_execute_postgresql_proc +go diff --git a/test/JDBC/expected/Test-sp_execute_postgresql.out b/test/JDBC/expected/Test-sp_execute_postgresql.out new file mode 100644 index 0000000000..2900499754 --- /dev/null +++ b/test/JDBC/expected/Test-sp_execute_postgresql.out @@ -0,0 +1,425 @@ +-- tsql +-- Throws an error if the argument is empty +exec sp_execute_postgresql NULL; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: statement cannot be NULL)~~ + + +exec sp_execute_postgresql ''; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: statement cannot be NULL)~~ + + +-- Throw error if extension statement is empty after removing trailing spaces +exec sp_execute_postgresql ' '; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: statement cannot be NULL)~~ + + +-- Throw error if no argument or more than 2 arguments are passed to sp_execute_postgresql procedure +exec sp_execute_postgresql; +go +~~ERROR (Code: 201)~~ + +~~ERROR (Message: procedure sp_execute_postgresql expects parameter "@postgresStmt", which was not supplied.)~~ + + +EXEC sp_execute_postgresql '', '',''; +go +~~ERROR (Code: 8144)~~ + +~~ERROR (Message: procedure sp_execute_postgresql has too many arguments specified.)~~ + + + +-- Creates extension even if extension statement contains leading/trailing spaces by removing trailing spaces +exec sp_execute_postgresql ' create extension pg_stat_statements '; +-- throw an error if more than one statement is passed +exec sp_execute_postgresql 'create extension pg_stat_statements with schema sys; create extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: expected 1 statement but got 2 statements after parsing)~~ + + +-- check if dialect, current_user and search_path are switched back to it's original values after error +select current_user +go +~~START~~ +varchar +dbo +~~END~~ + + +select current_setting('search_path') +go +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + + +select current_setting('babelfishpg_tsql.sql_dialect') +go +~~START~~ +text +tsql +~~END~~ + + +-- throw error if statements has syntax error +exec sp_execute_postgresql 'crete extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near "crete")~~ + + + +-- throw error if anything other than extension object is created +exec sp_execute_postgresql 'create table test(A int)' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: only create/alter/drop extension statements are currently supported in Babelfish)~~ + + +-- throw error if unprivileged login(does not have superuser as well as sysadmin) tries to create the extension +create login l1 with password = '12345678' +go + +-- tsql user=l1 password=12345678 +exec sp_execute_postgresql 'create extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied to create extension)~~ + + +-- 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) = 'l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + + +-- psql +select pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- tsql +drop login l1 +go + + +-- throw error if login does not have superuser privilege(it has only sysadmin) +create login l2 with password = '12345678' +go +-- grant role sysadmin +alter role sysadmin add member l2 +go + +-- tsql user=l2 password=12345678 +exec sp_execute_postgresql 'create extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied to create extension)~~ + + +-- 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) = 'l2' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + + +-- psql +select pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- tsql +drop login l2 +go + +-- Create extension +exec sp_execute_postgresql 'create extension if not exists pg_stat_statements'; +go +select extname from pg_extension where extname = 'pg_stat_statements' +go +~~START~~ +varchar +pg_stat_statements +~~END~~ + + +-- psql +ALTER SYSTEM SET pg_stat_statements.track = 'top'; +ALTER SYSTEM SET compute_query_id = 1; +SELECT pg_reload_conf(); +go +~~START~~ +bool +t +~~END~~ + + +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +SELECT pg_stat_statements_reset(); +go +~~START~~ +void + +~~END~~ + + +-- tsql +-- for accessing the extension we need to give schema qualifier i.e. [public].pg_stat_statements +SELECT toplevel, query, calls, rows, plans from [public].pg_stat_statements where queryid != 0 ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint#!#bigint +~~END~~ + + +-- create extension without using 'if not exists' option will throw error +exec sp_execute_postgresql 'create extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: extension "pg_stat_statements" already exists)~~ + +exec sp_execute_postgresql 'drop extension pg_stat_statements'; +go + +-- throw an error if user creates anything other than allowed extensions(tds_fdw, pg_stat_statements and fuzzystrmatch for now) +exec sp_execute_postgresql 'create extension pg_visibility'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'pg_visibility' extension creation is not supported)~~ + + +-- create extension with any schema other than user created schemas +-- non-babelfish schema +exec sp_execute_postgresql 'create extension pg_stat_statements with schema public'; +go + +exec sp_execute_postgresql 'drop extension pg_stat_statements'; +go + +-- user created schema +create schema sch1 +go + +-- throw error if try to create extension in user created schema +exec sp_execute_postgresql 'create extension pg_stat_statements with schema sch1' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: extension creation in 'sch1' is not supported from TSQL)~~ + + +-- babelfish schema +exec sp_execute_postgresql 'create extension pg_stat_statements with schema sys'; +go + +drop schema sch1 +go + +exec sp_execute_postgresql 'drop extension pg_stat_statements'; +go + +-- try extension creation after switching database context +create database sp_exec_psql_db1; +go + +use sp_exec_psql_db1; +go + +exec sp_execute_postgresql 'create extension pg_stat_statements;'; +go + +select nsp.nspname from pg_extension ext join pg_namespace nsp on ext.extnamespace=nsp.oid where ext.extname = 'pg_stat_statements'; +go +~~START~~ +varchar +public +~~END~~ + + +exec sp_execute_postgresql 'drop extension pg_stat_statements;'; +go + +use master; +go + +drop database sp_exec_psql_db1; +go + +-- cascade not supported yet, it will throw error +exec sp_execute_postgresql 'create extension pg_stat_statements with cascade'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'cascade' is not yet supported in Babelfish)~~ + + +-- create extension with any previous version +exec sp_execute_postgresql 'create extension pg_stat_statements with version "1.4"'; +go + +select extname, extversion from pg_extension where extname = 'pg_stat_statements' +go +~~START~~ +varchar#!#text +pg_stat_statements#!#1.4 +~~END~~ + + +-- alter extension version +exec sp_execute_postgresql 'alter extension pg_stat_statements update to "1.10"'; +go + +select extname, extversion from pg_extension where extname = 'pg_stat_statements' +go +~~START~~ +varchar#!#text +pg_stat_statements#!#1.10 +~~END~~ + + +-- throw an error if user tries to alter schema +exec sp_execute_postgresql 'alter extension pg_stat_statements set schema sys' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: alter extension schema is not currently supported in Babelfish)~~ + + +-- throw an error if user tries to Add/Drop objects in extension +create table demo(A int) +go +exec sp_execute_postgresql 'alter extension pg_stat_statements add table demo' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: alter extension to Add/Drop object in extension is not currently supported in Babelfish)~~ + +drop table demo +go + +-- throw error if we drop any other object other than extension +create table proc_tmp(A int) +go +exec sp_execute_postgresql 'drop table proc_tmp' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: only create/alter/drop extension statements are currently supported in Babelfish)~~ + +drop table proc_tmp +go + +-- cannot drop extension if other objects depend on it +create view pg_view as select query from [public].pg_stat_statements; +go + +exec sp_execute_postgresql 'drop extension pg_stat_statements' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot drop extension pg_stat_statements because other objects depend on it)~~ + +drop view pg_view +go + +exec sp_execute_postgresql 'drop extension pg_stat_statements'; +go + +-- drop extension without using 'if exists' option will throw error +exec sp_execute_postgresql 'drop extension pg_stat_statements'; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: extension "pg_stat_statements" does not exist)~~ + +-- drop extension using 'if exists' option +exec sp_execute_postgresql 'drop extension if exists pg_stat_statements'; +go + +exec sp_execute_postgresql 'create extension pg_stat_statements' +go + +-- Restrict option prevents the specified extensions from being dropped if other objects depend on table_schema +create view pg_view as select query from [public].pg_stat_statements; +go +exec sp_execute_postgresql 'drop extension pg_stat_statements restrict' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: cannot drop extension pg_stat_statements because other objects depend on it)~~ + +drop view pg_view +go + +exec sp_execute_postgresql 'drop extension pg_stat_statements'; +go + +-- check if dialect, current_user and search_path are switched back to it's default values +select current_user +go +~~START~~ +varchar +dbo +~~END~~ + + +select current_setting('search_path') +go +~~START~~ +text +master_dbo, "$user", sys, pg_catalog +~~END~~ + + +select current_setting('babelfishpg_tsql.sql_dialect') +go +~~START~~ +text +tsql +~~END~~ + diff --git a/test/JDBC/expected/Test-sp_helpuser-vu-verify.out b/test/JDBC/expected/Test-sp_helpuser-vu-verify.out index 47f613030e..bfe58c8b79 100644 --- a/test/JDBC/expected/Test-sp_helpuser-vu-verify.out +++ b/test/JDBC/expected/Test-sp_helpuser-vu-verify.out @@ -19,7 +19,7 @@ GO ~~START~~ varchar#!#varchar#!#int#!#varchar#!#varchar#!#nvarchar#!#int dbo#!#db_owner#!#1#!##!#dbo#!#dbo#!#1 -guest#!#public#!#0#!##!##!#guest#!#1 +guest#!#public#!#0#!##!#guest#!#guest#!#1 ~~END~~ diff --git a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out index 2f39f6364a..20379f7e2d 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-cleanup.out +++ b/test/JDBC/expected/Test-sp_rename-vu-cleanup.out @@ -11,7 +11,10 @@ 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_table_delim; GO DROP TABLE sp_rename_vu_schema1.sp_rename_vu_table1; @@ -44,5 +47,23 @@ 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 + +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..18717c0de1 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-prepare.out +++ b/test/JDBC/expected/Test-sp_rename-vu-prepare.out @@ -8,6 +8,12 @@ GO CREATE TABLE sp_rename_vu_table2(sp_rename_vu_t2_col1 int, sp_rename_vu_t2_col2 int); GO +SET quoted_identifier ON +GO + +CREATE TABLE sp_rename_vu_table_delim("sp_rename_vu_td1_col1" int, [sp_rename_vu_td1_col2] int); +GO + CREATE SCHEMA sp_rename_vu_schema1; GO @@ -72,7 +78,24 @@ START WITH 1 INCREMENT BY 1; GO -CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 +CREATE TRIGGER sp_rename_vu_trig1 ON sp_rename_vu_table2 AFTER INSERT, UPDATE AS -RAISERROR ('Testing sp_rename', 16, 10); +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 + +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 ff82337a55..9807d02358 100644 --- a/test/JDBC/expected/Test-sp_rename-vu-verify.out +++ b/test/JDBC/expected/Test-sp_rename-vu-verify.out @@ -9,11 +9,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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~~ @@ -46,11 +49,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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~~ @@ -74,11 +80,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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 +129,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 +171,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~~ @@ -276,11 +287,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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~~ @@ -293,11 +307,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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~~ @@ -310,11 +327,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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~~ @@ -347,11 +367,14 @@ ORDER BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME GO ~~START~~ nvarchar#!#nvarchar#!#varchar#!#varchar +master#!#dbo#!#sp_rename_vu_table_delim#!#BASE TABLE 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 +417,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,43 +452,395 @@ 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_table_delim#!#BASE TABLE +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_table_delim#!#BASE TABLE +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_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 -~~ERROR (Code: 33557097)~~ -~~ERROR (Message: Feature not supported: renaming object type Column)~~ +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 --- Index -EXEC sp_rename N'sp_rename_vu_index1', N'sp_rename_vu_index2', N'INDEX'; +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 -~~ERROR (Code: 33557097)~~ +~~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~~ -~~ERROR (Message: Feature not supported: renaming object type Index)~~ +INSERT INTO sp_rename_vu_table1(sp_rename_vu_t1_col1_new) VALUES (10); +GO +~~ROW COUNT: 1~~ --- Statistics -EXEC sp_rename 'sp_rename_vu_stat1', 'sp_rename_vu_stat2', 'STATISTICS'; + +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 Statistics)~~ +~~ERROR (Message: column "sp_rename_vu_s1_t2_wrong_col" does not exist)~~ + + +-- COLUMN: delimited identifer +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table_delim' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_td1_col1#!#dbo#!#sp_rename_vu_table_delim +sp_rename_vu_td1_col2#!#dbo#!#sp_rename_vu_table_delim +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_table_delim."sp_rename_vu_td1_col1"', 'sp_rename_vu_td1_col1_new', 'COLUMN'; +GO +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table_delim' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +sp_rename_vu_td1_col1_new#!#dbo#!#sp_rename_vu_table_delim +sp_rename_vu_td1_col2#!#dbo#!#sp_rename_vu_table_delim +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_table_delim.[sp_rename_vu_td1_col1_new]', '[sp_rename_vu_td1_col1_new]', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table_delim' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +[sp_rename_vu_td1_col1_new]#!#dbo#!#sp_rename_vu_table_delim +sp_rename_vu_td1_col2#!#dbo#!#sp_rename_vu_table_delim +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_table_delim."[sp_rename_vu_td1_col1_new]"', '[SP_rename_vu_td1_col1_MIXED]', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table_delim' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +[sp_rename_vu_td1_col1_mixed]#!#dbo#!#sp_rename_vu_table_delim +sp_rename_vu_td1_col2#!#dbo#!#sp_rename_vu_table_delim +~~END~~ + + +EXEC sp_rename 'sp_rename_vu_table_delim."[SP_rename_vu_td1_col1_MIXED]"', '[ SP_rename_vu_td1_col1_MIXED_spaces ]', 'COLUMN'; +GO + +SELECT COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME +FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'sp_rename_vu_table_delim' +ORDER BY COLUMN_NAME, TABLE_SCHEMA, TABLE_NAME; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +[ sp_rename_vu_td1_col1_mixed_spaces ]#!#dbo#!#sp_rename_vu_table_delim +sp_rename_vu_td1_col2#!#dbo#!#sp_rename_vu_table_delim +~~END~~ + + +SET quoted_identifier OFF +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 +~~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: Feature not supported: renaming object type User-defined Data Type alias)~~ +~~ERROR (Message: type "sp_rename_vu_alias1" does not exist)~~ --- Trigger -EXEC sp_rename 'sp_rename_vu_trig1', 'sp_rename_vu_trig2', 'OBJECT'; +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); +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 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Feature not supported: renaming object type Index)~~ + + +-- Statistics +EXEC sp_rename 'sp_rename_vu_stat1', 'sp_rename_vu_stat2', 'STATISTICS'; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: Feature not supported: renaming object type Trigger)~~ +~~ERROR (Message: Feature not supported: renaming object type Statistics)~~ diff --git a/test/JDBC/expected/TestDatatypeAggSort-vu-cleanup.out b/test/JDBC/expected/TestDatatypeAggSort-vu-cleanup.out new file mode 100644 index 0000000000..41de6d5c51 --- /dev/null +++ b/test/JDBC/expected/TestDatatypeAggSort-vu-cleanup.out @@ -0,0 +1,33 @@ +DROP VIEW TestDatatypeAggSort_vu_prepare_char_view_max +go +DROP VIEW TestDatatypeAggSort_vu_prepare_char_view_min +go +DROP VIEW TestDatatypeAggSort_vu_prepare_varchar_view_max +go +DROP VIEW TestDatatypeAggSort_vu_prepare_varchar_view_min +go +DROP VIEW TestDatatypeAggSort_vu_prepare_datetime_view_max +go +DROP VIEW TestDatatypeAggSort_vu_prepare_datetime_view_min +go +DROP VIEW TestDatatypeAggSort_vu_prepare_datetime2_view_max +go +DROP VIEW TestDatatypeAggSort_vu_prepare_datetime2_view_min +go +DROP VIEW TestDatatypeAggSort_vu_prepare_datetimeoffset_view_max +go +DROP VIEW TestDatatypeAggSort_vu_prepare_datetimeoffset_view_min +go +DROP VIEW TestDatatypeAggSort_vu_prepare_smalldatetime_view_max +go +DROP VIEW TestDatatypeAggSort_vu_prepare_smalldatetime_view_min +go + +DROP PROCEDURE TestDatatypeAggSort_vu_prepare_proc +go + +DROP TABLE TestDatatypeAggSort_vu_prepare_tbl +go + +DROP TABLE TestDatatypeAggSort_vu_prepare_tbl2 +go diff --git a/test/JDBC/expected/TestDatatypeAggSort-vu-prepare.out b/test/JDBC/expected/TestDatatypeAggSort-vu-prepare.out new file mode 100644 index 0000000000..e1c6d2c43b --- /dev/null +++ b/test/JDBC/expected/TestDatatypeAggSort-vu-prepare.out @@ -0,0 +1,165 @@ +CREATE TABLE TestDatatypeAggSort_vu_prepare_tbl ( + char_col CHAR(10), + varchar_col VARCHAR(10), + datetime_col DATETIME, + datetime2_col DATETIME2, + datetimeoffset_col DATETIMEOFFSET, + smalldatetime_col SMALLDATETIME, +); +go + +INSERT INTO TestDatatypeAggSort_vu_prepare_tbl VALUES ( + 'abc', 'abc', + '1900-01-01 00:00:00.000', + '1900-01-01 00:00:00.000', + '1900-01-01 00:00:00.000 +0:00', + '1900-01-01 00:00:00.000' +), ( + 'def', 'def', + '1950-01-01 00:00:00.000', + '1950-01-01 00:00:00.000', + '1950-01-01 00:00:00.000 +0:00', + '1950-01-01 00:00:00.000' +), ( + 'ghi', 'ghi', + '2000-01-01 00:00:00.000', + '2000-01-01 00:00:00.000', + '2000-01-01 00:00:00.000 +0:00', + '2000-01-01 00:00:00.000' +), ( + 'jkl', 'jkl', + '2005-01-01 00:00:00.000', + '2005-01-01 00:00:00.000', + '2005-01-01 00:00:00.000 +0:00', + '2005-01-01 00:00:00.000' +), ( + 'mno', 'mno', + '2010-01-01 00:00:00.000', + '2010-01-01 00:00:00.000', + '2010-01-01 00:00:00.000 +0:00', + '2010-01-01 00:00:00.000' +), ( + 'pqr', 'pqr', + '2015-01-01 00:00:00.000', + '2015-01-01 00:00:00.000', + '2015-01-01 00:00:00.000 +0:00', + '2015-01-01 00:00:00.000' +), ( + 'stu', 'stu', + '2020-01-01 00:00:00.000', + '2020-01-01 00:00:00.000', + '2020-01-01 00:00:00.000 +0:00', + '2020-01-01 00:00:00.000' +), ( + 'xyz', 'xyz', + '2023-11-06 00:00:00.000', + '2023-11-06 00:00:00.000', + '2023-11-06 00:00:00.000 +0:00', + '2023-11-06 00:00:00.000' +), ( + NULL, NULL, NULL, NULL, NULL, NULL +); +go +~~ROW COUNT: 9~~ + + +CREATE INDEX TestDatatypeAggSort_vu_prepare_char_idx ON TestDatatypeAggSort_vu_prepare_tbl (char_col) +go +CREATE INDEX TestDatatypeAggSort_vu_prepare_varchar_idx ON TestDatatypeAggSort_vu_prepare_tbl (varchar_col) +go +CREATE INDEX TestDatatypeAggSort_vu_prepare_datetime_idx ON TestDatatypeAggSort_vu_prepare_tbl (datetime_col) +go +CREATE INDEX TestDatatypeAggSort_vu_prepare_datetime2_idx ON TestDatatypeAggSort_vu_prepare_tbl (datetime2_col) +go +CREATE INDEX TestDatatypeAggSort_vu_prepare_datetimeoffset_idx ON TestDatatypeAggSort_vu_prepare_tbl (datetimeoffset_col) +go +CREATE INDEX TestDatatypeAggSort_vu_prepare_smalldatetime_idx ON TestDatatypeAggSort_vu_prepare_tbl (smalldatetime_col) +go + +CREATE VIEW TestDatatypeAggSort_vu_prepare_char_view_max AS +SELECT MAX(char_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go +CREATE VIEW TestDatatypeAggSort_vu_prepare_char_view_min AS +SELECT MIN(char_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go + +CREATE VIEW TestDatatypeAggSort_vu_prepare_varchar_view_max AS +SELECT MAX(varchar_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go +CREATE VIEW TestDatatypeAggSort_vu_prepare_varchar_view_min AS +SELECT MIN(varchar_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go + +CREATE VIEW TestDatatypeAggSort_vu_prepare_datetime_view_max AS +SELECT MAX(datetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go +CREATE VIEW TestDatatypeAggSort_vu_prepare_datetime_view_min AS +SELECT MIN(datetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go + +CREATE VIEW TestDatatypeAggSort_vu_prepare_datetime2_view_max AS +SELECT MAX(datetime2_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go +CREATE VIEW TestDatatypeAggSort_vu_prepare_datetime2_view_min AS +SELECT MIN(datetime2_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go + +CREATE VIEW TestDatatypeAggSort_vu_prepare_datetimeoffset_view_max AS +SELECT MAX(datetimeoffset_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go +CREATE VIEW TestDatatypeAggSort_vu_prepare_datetimeoffset_view_min AS +SELECT MIN(datetimeoffset_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go + +CREATE VIEW TestDatatypeAggSort_vu_prepare_smalldatetime_view_max AS +SELECT MAX(smalldatetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go +CREATE VIEW TestDatatypeAggSort_vu_prepare_smalldatetime_view_min AS +SELECT MIN(smalldatetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl +go + +CREATE TABLE TestDatatypeAggSort_vu_prepare_tbl2 ( + max_min VARCHAR(3), + char_col CHAR(10), + varchar_col VARCHAR(10), + datetime_col DATETIME, + datetime2_col DATETIME2(6), + datetimeoffset_col DATETIMEOFFSET, + smalldatetime_col SMALLDATETIME, +); +go + + + + + +CREATE PROCEDURE TestDatatypeAggSort_vu_prepare_proc AS +BEGIN + DECLARE @char_val CHAR(10) + DECLARE @varchar_val VARCHAR(10) + DECLARE @datetime_val DATETIME + DECLARE @datetime2_val DATETIME2 + DECLARE @datetimeoffset_val DATETIMEOFFSET + DECLARE @smalldatetime_val SMALLDATETIME + SET @char_val = (SELECT MAX(char_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @varchar_val = (SELECT MAX(varchar_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @datetime_val = (SELECT MAX(datetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @datetime2_val = (SELECT MAX(datetime2_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @datetimeoffset_val = (SELECT MAX(datetimeoffset_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @smalldatetime_val = (SELECT MAX(smalldatetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + INSERT INTO TestDatatypeAggSort_vu_prepare_tbl2 VALUES ( + 'max', @char_val, @varchar_val, @datetime_val, @datetime2_val, + @datetimeoffset_val, @smalldatetime_val + ) + SET @char_val = (SELECT MIN(char_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @varchar_val = (SELECT MIN(varchar_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @datetime_val = (SELECT MIN(datetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @datetime2_val = (SELECT MIN(datetime2_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @datetimeoffset_val = (SELECT MIN(datetimeoffset_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + SET @smalldatetime_val = (SELECT MIN(smalldatetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl) + INSERT INTO TestDatatypeAggSort_vu_prepare_tbl2 VALUES ( + 'min', @char_val, @varchar_val, @datetime_val, @datetime2_val, + @datetimeoffset_val, @smalldatetime_val + ) +END +go diff --git a/test/JDBC/expected/TestDatatypeAggSort-vu-verify.out b/test/JDBC/expected/TestDatatypeAggSort-vu-verify.out new file mode 100644 index 0000000000..c171e22f8a --- /dev/null +++ b/test/JDBC/expected/TestDatatypeAggSort-vu-verify.out @@ -0,0 +1,192 @@ +SELECT * FROM TestDatatypeAggSort_vu_prepare_char_view_max +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The string size for the given CHAR/NCHAR data is not defined. Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n))~~ + +SELECT * FROM TestDatatypeAggSort_vu_prepare_char_view_min +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The string size for the given CHAR/NCHAR data is not defined. Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n))~~ + + +SELECT * FROM TestDatatypeAggSort_vu_prepare_varchar_view_max +go +~~START~~ +varchar +xyz +~~END~~ + +SELECT * FROM TestDatatypeAggSort_vu_prepare_varchar_view_min +go +~~START~~ +varchar +abc +~~END~~ + + +SELECT * FROM TestDatatypeAggSort_vu_prepare_datetime_view_max +go +~~START~~ +datetime +2023-11-06 00:00:00.0 +~~END~~ + +SELECT * FROM TestDatatypeAggSort_vu_prepare_datetime_view_min +go +~~START~~ +datetime +1900-01-01 00:00:00.0 +~~END~~ + + +SELECT * FROM TestDatatypeAggSort_vu_prepare_datetime2_view_max +go +~~START~~ +datetime2 +2023-11-06 00:00:00.0000000 +~~END~~ + +SELECT * FROM TestDatatypeAggSort_vu_prepare_datetime2_view_min +go +~~START~~ +datetime2 +1900-01-01 00:00:00.0000000 +~~END~~ + + +SELECT * FROM TestDatatypeAggSort_vu_prepare_datetimeoffset_view_max +go +~~START~~ +datetimeoffset +2023-11-06 00:00:00.0000000 +00:00 +~~END~~ + +SELECT * FROM TestDatatypeAggSort_vu_prepare_datetimeoffset_view_min +go +~~START~~ +datetimeoffset +1900-01-01 00:00:00.0000000 +00:00 +~~END~~ + + +SELECT * FROM TestDatatypeAggSort_vu_prepare_smalldatetime_view_max +go +~~START~~ +smalldatetime +2023-11-06 00:00:00.0 +~~END~~ + +SELECT * FROM TestDatatypeAggSort_vu_prepare_smalldatetime_view_min +go +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + + +EXEC TestDatatypeAggSort_vu_prepare_proc +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +SELECT * FROM TestDatatypeAggSort_vu_prepare_tbl2 ORDER BY max_min +go +~~START~~ +varchar#!#char#!#varchar#!#datetime#!#datetime2#!#datetimeoffset#!#smalldatetime +max#!#xyz #!#xyz#!#2023-11-06 00:00:00.0#!#2023-11-06 00:00:00.000000#!#2023-11-06 00:00:00.0000000 +00:00#!#2023-11-06 00:00:00.0 +min#!#abc #!#abc#!#1900-01-01 00:00:00.0#!#1900-01-01 00:00:00.000000#!#1900-01-01 00:00:00.0000000 +00:00#!#1900-01-01 00:00:00.0 +~~END~~ + + +-- This is failing because of BABEL-4332 +SELECT MAX(char_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE varchar_col <= 'xxx' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The string size for the given CHAR/NCHAR data is not defined. Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n))~~ + +SELECT MIN(char_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE varchar_col <= 'xxx' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The string size for the given CHAR/NCHAR data is not defined. Please use an explicit CAST or CONVERT to CHAR(n)/NCHAR(n))~~ + + +SELECT MAX(varchar_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE varchar_col <= 'xxx' +go +~~START~~ +varchar +stu +~~END~~ + +SELECT MIN(varchar_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE varchar_col > 'xxx' +go +~~START~~ +varchar +xyz +~~END~~ + + +SELECT MAX(datetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE datetime_col <= '2020-12-31 23:59:59' +go +~~START~~ +datetime +2020-01-01 00:00:00.0 +~~END~~ + +SELECT MIN(datetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE datetime_col > '2020-12-31 23:59:59' +go +~~START~~ +datetime +2023-11-06 00:00:00.0 +~~END~~ + + +SELECT MAX(datetime2_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE datetime2_col <= '2020-12-31 23:59:59' +go +~~START~~ +datetime2 +2020-01-01 00:00:00.0000000 +~~END~~ + +SELECT MIN(datetime2_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE datetime2_col > '2020-12-31 23:59:59' +go +~~START~~ +datetime2 +2023-11-06 00:00:00.0000000 +~~END~~ + + +SELECT MAX(datetimeoffset_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE datetimeoffset_col <= '2020-12-31 23:59:59' +go +~~START~~ +datetimeoffset +2020-01-01 00:00:00.0000000 +00:00 +~~END~~ + +SELECT MIN(datetimeoffset_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE datetimeoffset_col > '2020-12-31 23:59:59' +go +~~START~~ +datetimeoffset +2023-11-06 00:00:00.0000000 +00:00 +~~END~~ + + +SELECT MAX(smalldatetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE smalldatetime_col <= '2020-12-31 23:59:59' +go +~~START~~ +smalldatetime +2020-01-01 00:00:00.0 +~~END~~ + +SELECT MIN(smalldatetime_col) FROM TestDatatypeAggSort_vu_prepare_tbl WHERE smalldatetime_col > '2020-12-31 23:59:59' +go +~~START~~ +smalldatetime +2023-11-06 00:00:00.0 +~~END~~ + diff --git a/test/JDBC/expected/TestDatatypeAggSort.out b/test/JDBC/expected/TestDatatypeAggSort.out new file mode 100644 index 0000000000..da15e7c074 --- /dev/null +++ b/test/JDBC/expected/TestDatatypeAggSort.out @@ -0,0 +1,273 @@ +-- MAX/MIN functionality already verified in upgrade scripts. +-- This test mainly focuses on query plans. +CREATE TABLE TestDatatypeAggSort_tbl ( + char_col CHAR(10), + varchar_col VARCHAR(10), + datetime_col DATETIME, + datetime2_col DATETIME2, + datetimeoffset_col DATETIMEOFFSET, + smalldatetime_col SMALLDATETIME, +); +go + +INSERT INTO TestDatatypeAggSort_tbl VALUES ( + 'abc', 'abc', + '1900-01-01 00:00:00.000', + '1900-01-01 00:00:00.000', + '1900-01-01 00:00:00.000 +0:00', + '1900-01-01 00:00:00.000' +), ( + 'def', 'def', + '1950-01-01 00:00:00.000', + '1950-01-01 00:00:00.000', + '1950-01-01 00:00:00.000 +0:00', + '1950-01-01 00:00:00.000' +), ( + 'ghi', 'ghi', + '2000-01-01 00:00:00.000', + '2000-01-01 00:00:00.000', + '2000-01-01 00:00:00.000 +0:00', + '2000-01-01 00:00:00.000' +), ( + 'jkl', 'jkl', + '2005-01-01 00:00:00.000', + '2005-01-01 00:00:00.000', + '2005-01-01 00:00:00.000 +0:00', + '2005-01-01 00:00:00.000' +), ( + 'mno', 'mno', + '2010-01-01 00:00:00.000', + '2010-01-01 00:00:00.000', + '2010-01-01 00:00:00.000 +0:00', + '2010-01-01 00:00:00.000' +), ( + 'pqr', 'pqr', + '2015-01-01 00:00:00.000', + '2015-01-01 00:00:00.000', + '2015-01-01 00:00:00.000 +0:00', + '2015-01-01 00:00:00.000' +), ( + 'stu', 'stu', + '2020-01-01 00:00:00.000', + '2020-01-01 00:00:00.000', + '2020-01-01 00:00:00.000 +0:00', + '2020-01-01 00:00:00.000' +), ( + 'xyz', 'xyz', + '2023-11-06 00:00:00.000', + '2023-11-06 00:00:00.000', + '2023-11-06 00:00:00.000 +0:00', + '2023-11-06 00:00:00.000' +), ( + NULL, NULL, NULL, NULL, NULL, NULL +); +go +~~ROW COUNT: 9~~ + + +CREATE INDEX TestDatatypeAggSort_char_idx ON TestDatatypeAggSort_tbl (char_col) +go +CREATE INDEX TestDatatypeAggSort_varchar_idx ON TestDatatypeAggSort_tbl (varchar_col) +go +CREATE INDEX TestDatatypeAggSort_datetime_idx ON TestDatatypeAggSort_tbl (datetime_col) +go +CREATE INDEX TestDatatypeAggSort_datetime2_idx ON TestDatatypeAggSort_tbl (datetime2_col) +go +CREATE INDEX TestDatatypeAggSort_datetimeoffset_idx ON TestDatatypeAggSort_tbl (datetimeoffset_col) +go +CREATE INDEX TestDatatypeAggSort_smalldatetime_idx ON TestDatatypeAggSort_tbl (smalldatetime_col) +go + + +-- Check query plans, all aggregations should be optimized +-- into LIMIT + index scan. +SELECT set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + +SELECT set_config('enable_seqscan', 'off', false) +go +~~START~~ +text +off +~~END~~ + +SET babelfish_showplan_all ON +go + +-- This is failing because of BABEL-4332 +SELECT MAX(char_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col <= 'xxx' +go +~~START~~ +text +Query Text: SELECT MAX(char_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col <= 'xxx' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Scan Backward using testdatatypeaggsort_char_idxtesfbaa28928b545e2adef99cfdad96bca2 on testdatatypeaggsort_tbl + Index Cond: (char_col IS NOT NULL) + Filter: (varchar_col <= 'xxx'::"varchar") +~~END~~ + +SELECT MIN(char_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col <= 'xxx' +go +~~START~~ +text +Query Text: SELECT MIN(char_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col <= 'xxx' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Scan using testdatatypeaggsort_char_idxtesfbaa28928b545e2adef99cfdad96bca2 on testdatatypeaggsort_tbl + Index Cond: (char_col IS NOT NULL) + Filter: (varchar_col <= 'xxx'::"varchar") +~~END~~ + + +SELECT MAX(varchar_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col <= 'xxx' +go +~~START~~ +text +Query Text: SELECT MAX(varchar_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col <= 'xxx' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan Backward using testdatatypeaggsort_varchar_idx9ad0e932a2f10239b7debb0a3f366a92 on testdatatypeaggsort_tbl + Index Cond: ((varchar_col IS NOT NULL) AND (varchar_col <= 'xxx'::"varchar")) +~~END~~ + +SELECT MIN(varchar_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col > 'xxx' +go +~~START~~ +text +Query Text: SELECT MIN(varchar_col) FROM TestDatatypeAggSort_tbl WHERE varchar_col > 'xxx' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan using testdatatypeaggsort_varchar_idx9ad0e932a2f10239b7debb0a3f366a92 on testdatatypeaggsort_tbl + Index Cond: ((varchar_col IS NOT NULL) AND (varchar_col > 'xxx'::"varchar")) +~~END~~ + + +SELECT MAX(datetime_col) FROM TestDatatypeAggSort_tbl WHERE datetime_col <= '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MAX(datetime_col) FROM TestDatatypeAggSort_tbl WHERE datetime_col <= '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan Backward using testdatatypeaggsort_datetime_id059c1f40bc288b4812242508f8efa093 on testdatatypeaggsort_tbl + Index Cond: ((datetime_col IS NOT NULL) AND (datetime_col <= '2020-12-31 23:59:59'::datetime)) +~~END~~ + +SELECT MIN(datetime_col) FROM TestDatatypeAggSort_tbl WHERE datetime_col > '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MIN(datetime_col) FROM TestDatatypeAggSort_tbl WHERE datetime_col > '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan using testdatatypeaggsort_datetime_id059c1f40bc288b4812242508f8efa093 on testdatatypeaggsort_tbl + Index Cond: ((datetime_col IS NOT NULL) AND (datetime_col > '2020-12-31 23:59:59'::datetime)) +~~END~~ + + +SELECT MAX(datetime2_col) FROM TestDatatypeAggSort_tbl WHERE datetime2_col <= '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MAX(datetime2_col) FROM TestDatatypeAggSort_tbl WHERE datetime2_col <= '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan Backward using testdatatypeaggsort_datetime2_i1725d75058c0b3bc1047ac8734b677ec on testdatatypeaggsort_tbl + Index Cond: ((datetime2_col IS NOT NULL) AND (datetime2_col <= '2020-12-31 23:59:59'::datetime2)) +~~END~~ + +SELECT MIN(datetime2_col) FROM TestDatatypeAggSort_tbl WHERE datetime2_col > '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MIN(datetime2_col) FROM TestDatatypeAggSort_tbl WHERE datetime2_col > '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan using testdatatypeaggsort_datetime2_i1725d75058c0b3bc1047ac8734b677ec on testdatatypeaggsort_tbl + Index Cond: ((datetime2_col IS NOT NULL) AND (datetime2_col > '2020-12-31 23:59:59'::datetime2)) +~~END~~ + + +SELECT MAX(datetimeoffset_col) FROM TestDatatypeAggSort_tbl WHERE datetimeoffset_col <= '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MAX(datetimeoffset_col) FROM TestDatatypeAggSort_tbl WHERE datetimeoffset_col <= '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan Backward using testdatatypeaggsort_datetimeoffc266914d4bc72ff84892083238ed8c64 on testdatatypeaggsort_tbl + Index Cond: ((datetimeoffset_col IS NOT NULL) AND (datetimeoffset_col <= '2020-12-31 23:59:59 +00:00'::datetimeoffset)) +~~END~~ + +SELECT MIN(datetimeoffset_col) FROM TestDatatypeAggSort_tbl WHERE datetimeoffset_col > '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MIN(datetimeoffset_col) FROM TestDatatypeAggSort_tbl WHERE datetimeoffset_col > '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan using testdatatypeaggsort_datetimeoffc266914d4bc72ff84892083238ed8c64 on testdatatypeaggsort_tbl + Index Cond: ((datetimeoffset_col IS NOT NULL) AND (datetimeoffset_col > '2020-12-31 23:59:59 +00:00'::datetimeoffset)) +~~END~~ + + +SELECT MAX(smalldatetime_col) FROM TestDatatypeAggSort_tbl WHERE smalldatetime_col <= '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MAX(smalldatetime_col) FROM TestDatatypeAggSort_tbl WHERE smalldatetime_col <= '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan Backward using testdatatypeaggsort_smalldateti2dc63bb7d48110e1d7497e0fb6e1aad7 on testdatatypeaggsort_tbl + Index Cond: ((smalldatetime_col IS NOT NULL) AND (smalldatetime_col <= '2021-01-01 00:00:00'::smalldatetime)) +~~END~~ + +SELECT MIN(smalldatetime_col) FROM TestDatatypeAggSort_tbl WHERE smalldatetime_col > '2020-12-31 23:59:59' +go +~~START~~ +text +Query Text: SELECT MIN(smalldatetime_col) FROM TestDatatypeAggSort_tbl WHERE smalldatetime_col > '2020-12-31 23:59:59' +Result + InitPlan 1 (returns $0) + -> Limit + -> Index Only Scan using testdatatypeaggsort_smalldateti2dc63bb7d48110e1d7497e0fb6e1aad7 on testdatatypeaggsort_tbl + Index Cond: ((smalldatetime_col IS NOT NULL) AND (smalldatetime_col > '2021-01-01 00:00:00'::smalldatetime)) +~~END~~ + + +-- Reset +SET babelfish_showplan_all OFF +go +SELECT set_config('enable_seqscan', 'on', false) +go +~~START~~ +text +on +~~END~~ + +SELECT set_config('babelfishpg_tsql.explain_costs', 'on', false) +go +~~START~~ +text +on +~~END~~ + + +DROP TABLE TestDatatypeAggSort_tbl +go 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..6a9a9d3e22 --- /dev/null +++ b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-prepare.out @@ -0,0 +1,632 @@ +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)~~ + + +-- 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, 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 + +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..56817beab8 --- /dev/null +++ b/test/JDBC/expected/TestDatetime-numeric-dateaddfunction-vu-verify.out @@ -0,0 +1,309 @@ +-- 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 + +-- 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 + +-- 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 : +-- 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~~ +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_view8 +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 +~~START~~ +datetime +1901-01-02 00:00:00.0 +~~END~~ + + +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/TestDatetime-vu-verify.out b/test/JDBC/expected/TestDatetime-vu-verify.out index 3c05c128a6..a54b90e89e 100644 --- a/test/JDBC/expected/TestDatetime-vu-verify.out +++ b/test/JDBC/expected/TestDatetime-vu-verify.out @@ -276,3 +276,22 @@ datetime ~~END~~ + +select convert(datetime, '1900-01-01 02:18:53.003') +~~START~~ +datetime +1900-01-01 02:18:53.003 +~~END~~ + +select convert(datetime, '1900-01-02 00:00:00.003') +~~START~~ +datetime +1900-01-02 00:00:00.003 +~~END~~ + +select convert(datetime, '1900-01-02 01:00:00.003') +~~START~~ +datetime +1900-01-02 01:00:00.003 +~~END~~ + diff --git a/test/JDBC/expected/TestDatetime.out b/test/JDBC/expected/TestDatetime.out index 6eac2afbd6..0c213d5928 100644 --- a/test/JDBC/expected/TestDatetime.out +++ b/test/JDBC/expected/TestDatetime.out @@ -395,3 +395,22 @@ datetime ~~END~~ + +select convert(datetime, '1900-01-01 02:18:53.003') +~~START~~ +datetime +1900-01-01 02:18:53.003 +~~END~~ + +select convert(datetime, '1900-01-02 00:00:00.003') +~~START~~ +datetime +1900-01-02 00:00:00.003 +~~END~~ + +select convert(datetime, '1900-01-02 01:00:00.003') +~~START~~ +datetime +1900-01-02 01:00:00.003 +~~END~~ + diff --git a/test/JDBC/expected/TestDatetimeoffset-vu-verify.out b/test/JDBC/expected/TestDatetimeoffset-vu-verify.out index 2b51164ec6..3499bd7a22 100644 --- a/test/JDBC/expected/TestDatetimeoffset-vu-verify.out +++ b/test/JDBC/expected/TestDatetimeoffset-vu-verify.out @@ -293,14 +293,14 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime); go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99' AS datetime2) AS datetimeoffset); @@ -314,7 +314,7 @@ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS datetime2 go ~~START~~ datetime2 -1900-05-06 21:59:29.9980000 +1900-05-06 13:59:29.9980000 ~~END~~ @@ -381,7 +381,7 @@ select CAST(CAST('1900-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99 +0' AS datetimeoffset) AS time); @@ -416,7 +416,7 @@ select CAST(CAST('2050-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ @@ -425,21 +425,21 @@ select CAST(CAST('2000-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS smalldate go ~~START~~ smalldatetime -2000-06-07 09:29:00.0 +2000-06-06 23:59:00.0 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -2079-06-06 15:59:00.0 +2079-06-06 23:59:00.0 ~~END~~ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -1900-05-06 21:59:00.0 +1900-05-06 13:59:00.0 ~~END~~ select CAST(CAST('2020-03-15 23:59:29.99' AS smalldatetime) AS datetimeoffset); diff --git a/test/JDBC/expected/TestErrorHelperFunctions.out b/test/JDBC/expected/TestErrorHelperFunctions.out index c4963c72d3..049b0a2c38 100644 --- a/test/JDBC/expected/TestErrorHelperFunctions.out +++ b/test/JDBC/expected/TestErrorHelperFunctions.out @@ -75,6 +75,7 @@ P0001#!#%s#!#is not supported for conversions from#!#9809 25P01#!#%s can only be used in transaction blocks#!#SAVEPOINT#!#628 25P01#!#%s can only be used in transaction blocks#!#ROLLBACK TO SAVEPOINT#!#3903 25001#!#%s cannot run inside a transaction block#!##!#574 +25001#!#%s command cannot be used inside user transactions.#!##!#6615 42809#!#"%s" is not a table or materialized view#!##!#10610 42809#!#cannot create index on relation "%s"#!##!#10610 42809#!#%s parameter should be of %s type#!##!#16902 @@ -199,6 +200,12 @@ XX000#!#The table-valued parameter "%s" must be declared with the READONLY optio 42P01#!#table "%s" does not exist#!##!#3701 42P13#!#PL/tsql functions cannot return type %s#!##!#2733 0A000#!#Column name or number of supplied values does not match table definition.#!##!#213 +42501#!#Only members of the sysadmin role can execute this stored procedure.#!##!#15003 +42809#!#The target "%s" of the OUTPUT INTO clause cannot be a view or common table expression.#!##!#330 +22008#!#The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart#!##!#535 +22023#!#'%s' is not a recognized %s option#!##!#155 +22023#!#The datepart %s is not supported by date function %s for data type %s.#!##!#9810 +22008#!#Adding a value to a '%s' column caused an overflow.#!##!#517 ~~END~~ diff --git a/test/JDBC/expected/TestErrorHelperFunctionsUpgrade-vu-verify.out b/test/JDBC/expected/TestErrorHelperFunctionsUpgrade-vu-verify.out index b70f687722..b33c88085d 100644 --- a/test/JDBC/expected/TestErrorHelperFunctionsUpgrade-vu-verify.out +++ b/test/JDBC/expected/TestErrorHelperFunctionsUpgrade-vu-verify.out @@ -24,6 +24,7 @@ int 289 293 306 +330 346 352 477 @@ -32,6 +33,7 @@ int 512 515 517 +535 545 547 550 @@ -77,6 +79,7 @@ int 4901 4920 6401 +6615 8003 8004 8007 @@ -109,6 +112,7 @@ int 9441 9451 9809 +9810 10610 10727 10733 @@ -123,6 +127,7 @@ int 11708 11709 11717 +15003 16901 16902 16903 @@ -177,6 +182,7 @@ int 628 3903 574 +6615 10610 10610 16902 @@ -301,6 +307,12 @@ int 3701 2733 213 +15003 +330 +535 +155 +9810 +517 ~~END~~ @@ -340,6 +352,7 @@ int 628 3903 574 +6615 10610 10610 16902 @@ -464,6 +477,12 @@ int 3701 2733 213 +15003 +330 +535 +155 +9810 +517 ~~END~~ @@ -471,6 +490,6 @@ EXEC TestErrorHelperFunctionsUpgrade_VU_PREPARE_PROC GO ~~START~~ int -156 +163 ~~END~~ diff --git a/test/JDBC/expected/TestIsolationLevels.out b/test/JDBC/expected/TestIsolationLevels.out index 0d5e21740c..83a45c4950 100644 --- a/test/JDBC/expected/TestIsolationLevels.out +++ b/test/JDBC/expected/TestIsolationLevels.out @@ -1,3 +1,17 @@ +SELECT set_config('babelfishpg_tsql.isolation_level_repeatable_read','off',false); +SELECT set_config('babelfishpg_tsql.isolation_level_serializable','off',false); +GO +~~START~~ +text +off +~~END~~ + +~~START~~ +text +off +~~END~~ + + set transaction isolation level read uncommitted; go @@ -8,7 +22,7 @@ set transaction isolation level repeatable read; go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: REPEATABLE READ isolation level is not supported)~~ +~~ERROR (Message: Isolation level ‘REPEATABLE READ’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_repeatable_read’ config option to get PG repeatable read isolation level.)~~ set transaction isolation level snapshot; @@ -18,7 +32,7 @@ set transaction isolation level serializable; go ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: SERIALIZABLE isolation level is not supported)~~ +~~ERROR (Message: Isolation level ‘SERIALIZABLE’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_serializable’ config option to get PG serializable isolation level.)~~ select set_config('default_transaction_isolation', 'read uncommitted', false); diff --git a/test/JDBC/expected/TestProcedureWithTriggers.out b/test/JDBC/expected/TestProcedureWithTriggers.out index c3f0a8ab8c..4fd9c994fa 100644 --- a/test/JDBC/expected/TestProcedureWithTriggers.out +++ b/test/JDBC/expected/TestProcedureWithTriggers.out @@ -88,29 +88,9 @@ int#!#varchar EXEC psql_interop_proc2 GO -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 4~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 2~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 5~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ +~~ERROR (Code: 33557097)~~ -~~ROW COUNT: 2~~ +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ SELECT * from triggerTab2 ORDER BY c1; GO @@ -123,22 +103,32 @@ int -- psql currentSchema=master_dbo,public CALL tsql_interop_proc(); GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second');" +PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 0A000)~~ + SELECT * from triggerTab1 ORDER BY c1; GO ~~START~~ int4#!#varchar +5#!#first 5#!#third 6#!#second -9#!#third -10#!#second -13#!#first -13#!#third -14#!#second ~~END~~ CALL psql_interop_proc2(); GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second')" +PL/pgSQL function psql_interop_proc2() line 3 at SQL statement + Server SQLState: 0A000)~~ + SELECT * from triggerTab2 ORDER BY c1; GO ~~START~~ @@ -156,7 +146,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 10~~ +~~ROW COUNT: 4~~ ~~ROW COUNT: 3~~ @@ -170,7 +160,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 11~~ +~~ROW COUNT: 5~~ ~~ROW COUNT: 3~~ @@ -186,15 +176,9 @@ GO int#!#varchar 5#!#third 6#!#second +9#!#first 9#!#third 10#!#second -13#!#third -14#!#second -17#!#third -18#!#second -21#!#first -21#!#third -22#!#second ~~END~~ COMMIT @@ -205,24 +189,19 @@ BEGIN TRANSACTION GO CALL tsql_interop_proc(); GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second');" +PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 0A000)~~ + SELECT * from triggerTab1 ORDER BY c1; GO -~~START~~ -int4#!#varchar -5#!#third -6#!#second -9#!#third -10#!#second -13#!#third -14#!#second -17#!#third -18#!#second -21#!#third -22#!#second -25#!#first -25#!#third -26#!#second -~~END~~ +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: current transaction is aborted, commands ignored until end of transaction block + Server SQLState: 25P02)~~ ROLLBACK GO @@ -232,29 +211,9 @@ BEGIN TRANSACTION GO EXEC psql_interop_proc2 GO -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 12~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 2~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 13~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ +~~ERROR (Code: 33557097)~~ -~~ROW COUNT: 2~~ +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ SELECT * from triggerTab2 ORDER BY c1; GO @@ -265,18 +224,29 @@ int ROLLBACK GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK can only be used in transaction blocks)~~ + -- psql currentSchema=master_dbo,public BEGIN TRANSACTION GO CALL psql_interop_proc2(); GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second')" +PL/pgSQL function psql_interop_proc2() line 3 at SQL statement + Server SQLState: 0A000)~~ + SELECT * from triggerTab2 ORDER BY c1; GO -~~START~~ -int4 -2 -~~END~~ +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: current transaction is aborted, commands ignored until end of transaction block + Server SQLState: 25P02)~~ COMMIT GO @@ -288,53 +258,33 @@ SAVE TRANSACTION sp1; GO EXEC psql_interop_proc2 GO -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ +~~ERROR (Code: 33557097)~~ -~~ROW COUNT: 14~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 2~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 15~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 2~~ +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ ROLLBACK TRANSACTION sp1; GO +~~ERROR (Code: 3903)~~ + +~~ERROR (Message: ROLLBACK TO SAVEPOINT can only be used in transaction blocks)~~ + SELECT * from triggerTab1 ORDER BY c1; GO ~~START~~ int#!#varchar 5#!#third 6#!#second +9#!#first 9#!#third 10#!#second -13#!#third -14#!#second -17#!#third -18#!#second -21#!#third -22#!#second -25#!#first -25#!#third -26#!#second ~~END~~ COMMIT GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + -- tsql BEGIN TRANSACTION @@ -347,7 +297,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 14~~ +~~ROW COUNT: 6~~ ~~ROW COUNT: 3~~ @@ -361,7 +311,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 15~~ +~~ROW COUNT: 7~~ ~~ROW COUNT: 3~~ @@ -390,6 +340,13 @@ SAVEPOINT sp1; GO CALL tsql_interop_proc(); GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second');" +PL/tsql function tsql_interop_proc() line 1 at SQL statement + Server SQLState: 0A000)~~ + ROLLBACK TO sp1; GO SELECT * from triggerTab2 ORDER BY c1; @@ -420,7 +377,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 14~~ +~~ROW COUNT: 6~~ ~~ROW COUNT: 3~~ @@ -437,17 +394,9 @@ int#!#varchar 4#!#second 7#!#third 8#!#second +11#!#first 11#!#third 12#!#second -15#!#third -16#!#second -19#!#third -20#!#second -23#!#third -24#!#second -27#!#first -27#!#third -28#!#second ~~END~~ @@ -487,7 +436,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 15~~ +~~ROW COUNT: 7~~ ~~ROW COUNT: 3~~ @@ -501,7 +450,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 15~~ +~~ROW COUNT: 7~~ ~~ROW COUNT: 3~~ @@ -519,17 +468,9 @@ int#!#varchar 6#!#second 9#!#third 10#!#second +13#!#first 13#!#third 14#!#second -17#!#third -18#!#second -21#!#third -22#!#second -25#!#third -26#!#second -29#!#first -29#!#third -30#!#second ~~END~~ @@ -571,7 +512,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 16~~ +~~ROW COUNT: 8~~ ~~ROW COUNT: 3~~ @@ -585,7 +526,7 @@ GO ~~ROW COUNT: 1~~ -~~ROW COUNT: 17~~ +~~ROW COUNT: 9~~ ~~ROW COUNT: 3~~ @@ -604,17 +545,9 @@ int#!#varchar 8#!#second 11#!#third 12#!#second +15#!#first 15#!#third 16#!#second -19#!#third -20#!#second -23#!#third -24#!#second -27#!#third -28#!#second -31#!#first -31#!#third -32#!#second ~~END~~ @@ -693,13 +626,18 @@ GO -- psql currentSchema=master_dbo,public CALL psql_interop_proc2(); GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second')" +PL/pgSQL function psql_interop_proc2() line 3 at SQL statement + Server SQLState: 0A000)~~ + SELECT * FROM triggerTab1 ORDER BY c1; GO ~~START~~ int4#!#"sys"."varchar" -5#!#first -5#!#third -6#!#second +1#!#first ~~END~~ @@ -708,39 +646,23 @@ BEGIN TRANSACTION GO EXEC psql_interop_proc2; GO -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 4~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ +~~ERROR (Code: 33557097)~~ -~~ROW COUNT: 2~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 5~~ - -~~ROW COUNT: 3~~ - -~~ROW COUNT: 1~~ - -~~ROW COUNT: 2~~ +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ SELECT * FROM triggerTab2 ORDER BY c1; GO ~~START~~ int -2 +1 ~~END~~ COMMIT GO +~~ERROR (Code: 3902)~~ + +~~ERROR (Message: COMMIT can only be used in transaction blocks)~~ + -- tsql DROP TRIGGER txnTrig1; @@ -785,10 +707,10 @@ int#!#varchar ~~START~~ int -2 +1 ~~END~~ -~~ROW COUNT: 6~~ +~~ROW COUNT: 2~~ ~~ROW COUNT: 1~~ @@ -842,7 +764,7 @@ GO ~~START~~ int -4 +3 2 ~~END~~ @@ -858,7 +780,7 @@ GO int 2 4 -6 +5 ~~END~~ @@ -867,10 +789,10 @@ CALL tsql_interop_proc(); GO ~~ERROR (Code: 0)~~ -~~ERROR (Message: ERROR: invalid transaction command - Where: PL/tsql function txntrig1() line 1 at SQL statement +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(2, 'second');" PL/tsql function tsql_interop_proc() line 1 at SQL statement - Server SQLState: 2D000)~~ + Server SQLState: 0A000)~~ SELECT * from triggerTab2 ORDER BY c1; GO @@ -878,7 +800,7 @@ GO int4 2 4 -6 +5 ~~END~~ @@ -915,7 +837,7 @@ int#!#varchar ~~START~~ int -6 +5 4 2 ~~END~~ @@ -935,7 +857,7 @@ int 2 4 6 -8 +7 ~~END~~ @@ -944,10 +866,10 @@ CALL tsql_interop_proc(); GO ~~ERROR (Code: 0)~~ -~~ERROR (Message: ERROR: invalid transaction command - Where: PL/tsql function txntrig1() line 1 at SQL statement +~~ERROR (Message: ERROR: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger. + Where: SQL statement "INSERT INTO triggerTab1 VALUES(3, 'third');" PL/tsql function tsql_interop_proc() line 1 at SQL statement - Server SQLState: 2D000)~~ + Server SQLState: 0A000)~~ SELECT * from triggerTab1 ORDER BY c1; GO @@ -989,7 +911,7 @@ int#!#varchar ~~START~~ int -8 +7 6 4 2 @@ -1010,7 +932,7 @@ int 2 4 6 -8 +7 ~~END~~ @@ -1058,7 +980,7 @@ GO ~~START~~ int -8 +7 6 4 2 @@ -1081,7 +1003,7 @@ int 4 6 8 -10 +9 ~~END~~ @@ -1134,7 +1056,7 @@ int#!#varchar ~~START~~ int -10 +9 8 6 4 @@ -1160,7 +1082,7 @@ int 4 6 8 -10 +9 ~~END~~ @@ -1213,7 +1135,7 @@ int#!#varchar ~~START~~ int -10 +9 8 6 4 @@ -1241,7 +1163,7 @@ int 6 8 10 -12 +11 ~~END~~ @@ -1319,7 +1241,7 @@ datetime ~~START~~ int -14 +13 12 10 8 @@ -1333,7 +1255,7 @@ int ~~START~~ int -12 +11 10 8 6 @@ -1373,7 +1295,7 @@ int 6 8 10 -12 +11 ~~END~~ DROP TRIGGER txnTrig1; diff --git a/test/JDBC/expected/TestRecreatedInnerProcedures.out b/test/JDBC/expected/TestRecreatedInnerProcedures.out index bcf03d6faa..dbafce81d6 100644 --- a/test/JDBC/expected/TestRecreatedInnerProcedures.out +++ b/test/JDBC/expected/TestRecreatedInnerProcedures.out @@ -108,18 +108,16 @@ as insert into t1 values (1); go --- This has failed since PG14. exec psql_outer_proc; go -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: Calling an inner procedure failed)~~ +~~ROW COUNT: 1~~ select * from t1; go ~~START~~ int 1 +1 ~~END~~ @@ -190,20 +188,14 @@ end; $$ LANGUAGE PLPGSQL; go --- This has failed since PG14. call psql_outer_proc(); go -~~ERROR (Code: 0)~~ - -~~ERROR (Message: ERROR: Calling an inner procedure failed - Where: PL/pgSQL function psql_outer_proc() line 5 at RAISE - Server SQLState: P0001)~~ - select * from t1; go ~~START~~ int4 1 +1 ~~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/expected/TestSPExecutesql.out b/test/JDBC/expected/TestSPExecutesql.out index 1bfdb9cc94..f4819d28ff 100644 --- a/test/JDBC/expected/TestSPExecutesql.out +++ b/test/JDBC/expected/TestSPExecutesql.out @@ -177,6 +177,58 @@ datetime#!#datetime ~~END~~ +/* 8. Prefixed with dbo.<> and sys.<> */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC dbo.sp_executesql @SQLString; +go +~~START~~ +nvarchar +hello world +~~END~~ + + +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC sys.sp_executesql @SQLString; +go +~~START~~ +nvarchar +hello world +~~END~~ + + +/* 9. With omitted database and schema name */ +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC .dbo.sp_executesql @SQLString; +go +~~START~~ +nvarchar +hello world +~~END~~ + + +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC .sys.sp_executesql @SQLString; +go +~~START~~ +nvarchar +hello world +~~END~~ + + +DECLARE @SQLString NVARCHAR(100); +SET @SQLString = N'SELECT N''hello world'';'; +EXEC ..sp_executesql @SQLString; +go +~~START~~ +nvarchar +hello world +~~END~~ + + /* Exceptions */ /* 1. Wrong order of named/unnamed params */ DECLARE @SQLString NVARCHAR(100); diff --git a/test/JDBC/expected/TestStoredProcedures.out b/test/JDBC/expected/TestStoredProcedures.out index 976dea8e41..5381f7b9b2 100644 --- a/test/JDBC/expected/TestStoredProcedures.out +++ b/test/JDBC/expected/TestStoredProcedures.out @@ -239,3 +239,320 @@ DROP PROCEDURE sp_test14 #storedproc#!#prep#!#sp_test19#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c|-|output #storedproc#!#prep#!#sp_test19#!#uniqueidentifier|-|a|-|5b7c2e8d-6d90-411d-8e19-9a81067e6f6c|-|inputoutput #DROP PROCEDURE sp_test19 + +CREATE PROCEDURE sp_test20 (@a INT, @b INT OUTPUT) AS BEGIN SET @b=100; SET @a=1000; Select @a as a, @b as b; END; +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @b=@b OUT, @a=@a;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @b=@b, @a=@a OUT;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @b=@b OUT, @a=@a OUT;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @b=@b, @a=@a;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @a=@a, @b=@b;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @a=@a, @b=@b OUT;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @a=@a OUT, @b=@b;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @a=@a OUT, @b=@b OUT;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @a int;Declare @b int;Set @a=20;Set @b=10; exec sp_test20 @a OUT, @b OUT;select @a as a, @b as b; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|output +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|output#!#int|-|b|-|10|-|input +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|input +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|output#!#int|-|b|-|10|-|output +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|inputoutput#!#int|-|b|-|10|-|inputoutput +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|inputoutput +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +storedproc#!#prep#!#sp_test20#!#int|-|a|-|20|-|inputoutput#!#int|-|b|-|10|-|input +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +DROP PROCEDURE sp_test20 + +CREATE PROCEDURE sp_test21 (@a INT, @b INT OUTPUT, @d INT, @c INT OUTPUT) AS BEGIN SET @a=100; SET @b=200; SET @c=300; SET @d=400; Select @a as a, @b as b, @c as c, @d as d; END; +Declare @a int;Declare @b int;Declare @c int;Declare @d int;Set @a=20;Set @b=10;Set @c=5;Set @d=30; exec sp_test21 @b=@b OUT, @c=@c OUT, @a=@a, @d=@d; Select @a as a, @b as b, @c as c, @d as d; +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +~~START~~ +int#!#int#!#int#!#int +20#!#200#!#300#!#30 +~~END~~ + +Declare @a int;Declare @b int;Declare @c int;Declare @d int;Set @a=20;Set @b=10;Set @c=5;Set @d=30; exec sp_test21 @b=@b, @c=@c, @a=@a, @d=@d; Select @a as a, @b as b, @c as c, @d as d; +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +~~START~~ +int#!#int#!#int#!#int +20#!#10#!#5#!#30 +~~END~~ + +Declare @a int;Declare @b int;Declare @c int;Declare @d int;Set @a=20;Set @b=10;Set @c=5;Set @d=30; exec sp_test21 @c=@c OUT, @b=@b OUT, @a=@a, @d=@d; Select @a as a, @b as b, @c as c, @d as d; +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +~~START~~ +int#!#int#!#int#!#int +20#!#200#!#300#!#30 +~~END~~ + +Declare @a int;Declare @b int;Declare @c int;Declare @d int;Set @a=20;Set @b=10;Set @c=5;Set @d=30; exec sp_test21 @c=@c, @b=@b, @a=@a OUT, @d=@d OUT; Select @a as a, @b as b, @c as c, @d as d; +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +~~START~~ +int#!#int#!#int#!#int +20#!#10#!#5#!#30 +~~END~~ + +storedproc#!#prep#!#sp_test21#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|inputoutput#!#int|-|c|-|10|-|input#!#int|-|d|-|10|-|inputoutput +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +storedproc#!#prep#!#sp_test21#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|output#!#int|-|c|-|10|-|input#!#int|-|d|-|10|-|output +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +storedproc#!#prep#!#sp_test21#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|output#!#int|-|c|-|10|-|input#!#int|-|d|-|10|-|inputoutput +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +storedproc#!#prep#!#sp_test21#!#int|-|a|-|20|-|input#!#int|-|b|-|10|-|inputoutput#!#int|-|c|-|10|-|input#!#int|-|d|-|10|-|output +~~START~~ +int#!#int#!#int#!#int +100#!#200#!#300#!#400 +~~END~~ + +DROP PROCEDURE sp_test21 + +CREATE PROCEDURE sp_test22 (@MixedCaseArg_1 INT, @MixedCaseArg_2 INT OUTPUT) AS BEGIN SET @MixedCaseArg_2=100; SET @MixedCaseArg_1=1000; Select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; END; +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_2=@MixedCaseArg_2 OUT, @MixedCaseArg_1=@MixedCaseArg_1;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_2=@MixedCaseArg_2, @MixedCaseArg_1=@MixedCaseArg_1 OUT;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_2=@MixedCaseArg_2 OUT, @MixedCaseArg_1=@MixedCaseArg_1 OUT;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_2=@MixedCaseArg_2, @MixedCaseArg_1=@MixedCaseArg_1;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_1=@MixedCaseArg_1, @MixedCaseArg_2=@MixedCaseArg_2;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_1=@MixedCaseArg_1, @MixedCaseArg_2=@MixedCaseArg_2 OUT;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_1=@MixedCaseArg_1 OUT, @MixedCaseArg_2=@MixedCaseArg_2;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#10 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_1=@MixedCaseArg_1 OUT, @MixedCaseArg_2=@MixedCaseArg_2 OUT;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +Declare @MixedCaseArg_1 int;Declare @MixedCaseArg_2 int;Set @MixedCaseArg_1=20;Set @MixedCaseArg_2=10; exec sp_test22 @MixedCaseArg_1 OUT, @MixedCaseArg_2 OUT;select @MixedCaseArg_1 as MixedCaseArg_1, @MixedCaseArg_2 as MixedCaseArg_2; +~~START~~ +int#!#int +1000#!#100 +~~END~~ + +~~START~~ +int#!#int +20#!#100 +~~END~~ + +DROP PROCEDURE sp_test22 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/TestTransactionsSQLBatch.out b/test/JDBC/expected/TestTransactionsSQLBatch.out index c60f47da53..5db75c6d93 100644 --- a/test/JDBC/expected/TestTransactionsSQLBatch.out +++ b/test/JDBC/expected/TestTransactionsSQLBatch.out @@ -2,6 +2,7 @@ create table TxnTable(c1 int); # Begin transaction -> commit transaction begin transaction; +set transaction isolation level read committed; select @@trancount; ~~START~~ int @@ -15,7 +16,6 @@ int 2 ~~END~~ -set transaction isolation level read committed; #show transaction_isolation; #show default_transaction_isolation; insert into TxnTable values(1); @@ -71,6 +71,7 @@ int # Begin tran -> rollback tran begin tran; +set transaction isolation level read uncommitted; select @@trancount; ~~START~~ int @@ -78,7 +79,6 @@ int ~~END~~ begin tran; -set transaction isolation level read uncommitted; #show transaction_isolation; #show default_transaction_isolation; insert into TxnTable values(3); @@ -108,7 +108,7 @@ int set transaction isolation level repeatable read; ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: REPEATABLE READ isolation level is not supported)~~ +~~ERROR (Message: Isolation level ‘REPEATABLE READ’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_repeatable_read’ config option to get PG repeatable read isolation level.)~~ #show transaction_isolation; #show default_transaction_isolation; @@ -374,7 +374,7 @@ int set transaction isolation level serializable; ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: SERIALIZABLE isolation level is not supported)~~ +~~ERROR (Message: Isolation level ‘SERIALIZABLE’ is not currently supported in Babelfish. Please use ‘babelfishpg_tsql.isolation_level_serializable’ config option to get PG serializable isolation level.)~~ #show transaction_isolation; #show default_transaction_isolation; diff --git a/test/JDBC/expected/TestTriggerInteroperability.out b/test/JDBC/expected/TestTriggerInteroperability.out new file mode 100644 index 0000000000..2aa1bedc1d --- /dev/null +++ b/test/JDBC/expected/TestTriggerInteroperability.out @@ -0,0 +1,451 @@ +-- tsql +create table test_tbl_trig_bbf_1(a int); +create table test_tbl_trig_bbf_2(a int); +GO + +-- psql +create table master_dbo.psql_tbl_1(a int unique); +create table master_dbo.psql_tbl_2(a int); +GO + +-- psql +grant all on master_dbo.psql_tbl_1 to public; +GO + +-- psql +CREATE OR REPLACE FUNCTION master_dbo.f_trig_pg_1() RETURNS trigger +AS $$ +BEGIN + insert into master_dbo.psql_tbl_1 values (1); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; +GO + +-- psql +CREATE OR REPLACE FUNCTION master_dbo.f_trig_pg_2() RETURNS trigger +AS $$ +BEGIN + insert into master_dbo.psql_tbl_2 values (1); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; +GO + +-- psql +CREATE TRIGGER pg_trigger_1 AFTER INSERT OR DELETE OR UPDATE ON master_dbo.test_tbl_trig_bbf_1 + FOR EACH ROW EXECUTE FUNCTION master_dbo.f_trig_pg_1(); +GO + +-- psql +CREATE TRIGGER pg_trigger_2 AFTER INSERT OR DELETE OR UPDATE ON master_dbo.test_tbl_trig_bbf_2 + FOR EACH ROW EXECUTE FUNCTION master_dbo.f_trig_pg_2(); +GO + +-- tsql +begin tran; +GO + +insert into test_tbl_trig_bbf_1 values (1); +GO +~~ROW COUNT: 1~~ + + +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + + +commit tran; +GO + +select count(*) from test_tbl_trig_bbf_1; +GO +~~START~~ +int +1 +~~END~~ + + +select count(*) from psql_tbl_1; +GO +~~START~~ +int +1 +~~END~~ + + +begin tran; +GO + +-- should throw permission denied error +insert into test_tbl_trig_bbf_2 values (1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: permission denied for table psql_tbl_2)~~ + + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +rollback tran; +GO + +select count(*) from test_tbl_trig_bbf_2; +GO +~~START~~ +int +0 +~~END~~ + + +begin tran; +GO + +-- should throw duplicte entry error +insert into test_tbl_trig_bbf_1 values (1); +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "psql_tbl_1_a_key")~~ + + +select @@trancount; +GO +~~START~~ +int +1 +~~END~~ + + +rollback tran; +GO + +select count(*) from test_tbl_trig_bbf_1; +GO +~~START~~ +int +1 +~~END~~ + + +select count(*) from psql_tbl_1; +GO +~~START~~ +int +1 +~~END~~ + + +-- psql +truncate table master_dbo.psql_tbl_1; +truncate table master_dbo.psql_tbl_2; +GO + +-- tsql +create table test_tbl_trig_bbf_3(a int); +GO + +CREATE TRIGGER tsql_trigger_3 ON test_tbl_trig_bbf_3 AFTER INSERT AS +INSERT INTO test_tbl_trig_bbf_1 VALUES(4); +GO + +-- psql +CREATE PROCEDURE master_dbo.psql_interop_proc1() +AS +$$ +BEGIN + insert into test_tbl_trig_bbf_3 values (1); +END +$$ LANGUAGE PLPGSQL; +GO + +-- tsql +-- begin tsql insert -> tsql trigger -> pg trigger (without error) +begin tran +GO + +insert into test_tbl_trig_bbf_3 values (1); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +commit tran +GO + +select count(*) from test_tbl_trig_bbf_3; +GO +~~START~~ +int +1 +~~END~~ + + +select count(*) from test_tbl_trig_bbf_1; +GO +~~START~~ +int +2 +~~END~~ + + +select count(*) from psql_tbl_1; +GO +~~START~~ +int +1 +~~END~~ + + +-- PG proc --> insert --> tsql trigger --> should result in error +exec psql_interop_proc1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ + + +-- begin tsql insert -> tsql trigger -> pg trigger (error) +begin tran +GO + +insert into test_tbl_trig_bbf_3 values (1); +GO +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "psql_tbl_1_a_key")~~ + + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +rollback tran +GO + +select count(*) from test_tbl_trig_bbf_3; +GO +~~START~~ +int +1 +~~END~~ + + +select count(*) from test_tbl_trig_bbf_1; +GO +~~START~~ +int +2 +~~END~~ + + +select count(*) from psql_tbl_1; +GO +~~START~~ +int +1 +~~END~~ + + +-- psql +truncate table master_dbo.psql_tbl_1; +truncate table master_dbo.psql_tbl_2; +drop procedure master_dbo.psql_interop_proc1; +GO + +-- tsql +create table test_tbl_trig_bbf_4(a int); +GO + +CREATE PROCEDURE tsql_interop_proc +AS +insert into test_tbl_trig_bbf_4 values (1); +GO + +-- psql +CREATE OR REPLACE FUNCTION master_dbo.f_trig_pg_4() RETURNS trigger +AS $$ +BEGIN + insert into master_dbo.test_tbl_trig_bbf_3 values (1); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; +GO + +CREATE TRIGGER pg_trigger_4 AFTER INSERT OR DELETE OR UPDATE ON master_dbo.test_tbl_trig_bbf_4 + FOR EACH ROW EXECUTE FUNCTION master_dbo.f_trig_pg_4(); +GO + + +-- tsql +-- begin TSQL insert -> PG trigger -> TSQL trigger -> PG trigger (without error) +begin tran +go + +insert into test_tbl_trig_bbf_4 values (1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ + + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +commit tran +GO + +select count(*) from test_tbl_trig_bbf_4; +GO +~~START~~ +int +0 +~~END~~ + + +select count(*) from test_tbl_trig_bbf_3; +GO +~~START~~ +int +1 +~~END~~ + + +select count(*) from test_tbl_trig_bbf_1; +GO +~~START~~ +int +2 +~~END~~ + + +select count(*) from psql_tbl_1; +GO +~~START~~ +int +0 +~~END~~ + + +-- tsql proc --> insert --> PG trigger --> tsql trigger (should result in error) +-- tsql +exec tsql_interop_proc; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ + + +-- tsql + +drop procedure tsql_interop_proc; +-- begin TSQL insert -> PG trigger -> TSQL trigger -> PG trigger (error) +begin tran +go + +insert into test_tbl_trig_bbf_4 values (1); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: T-SQL trigger can not be executed from PostgreSQL function, procedure or trigger.)~~ + + +select @@trancount +GO +~~START~~ +int +1 +~~END~~ + + +rollback tran +GO + +select count(*) from test_tbl_trig_bbf_4; +GO +~~START~~ +int +0 +~~END~~ + + +select count(*) from test_tbl_trig_bbf_3; +GO +~~START~~ +int +1 +~~END~~ + + +select count(*) from test_tbl_trig_bbf_1; +GO +~~START~~ +int +2 +~~END~~ + + +select count(*) from psql_tbl_1; +GO +~~START~~ +int +0 +~~END~~ + + +-- psql +drop function master_dbo.f_trig_pg_1() cascade; +drop function master_dbo.f_trig_pg_2() cascade; +drop function master_dbo.f_trig_pg_4() cascade; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: drop cascades to trigger pg_trigger_1 on table master_dbo.test_tbl_trig_bbf_1 Server SQLState: 00000)~~~~WARNING (Message: drop cascades to trigger pg_trigger_2 on table master_dbo.test_tbl_trig_bbf_2 Server SQLState: 00000)~~~~WARNING (Message: drop cascades to trigger pg_trigger_4 on table master_dbo.test_tbl_trig_bbf_4 Server SQLState: 00000)~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: drop cascades to trigger pg_trigger_1 on table master_dbo.test_tbl_trig_bbf_1 Server SQLState: 00000)~~~~WARNING (Message: drop cascades to trigger pg_trigger_2 on table master_dbo.test_tbl_trig_bbf_2 Server SQLState: 00000)~~~~WARNING (Message: drop cascades to trigger pg_trigger_4 on table master_dbo.test_tbl_trig_bbf_4 Server SQLState: 00000)~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: drop cascades to trigger pg_trigger_1 on table master_dbo.test_tbl_trig_bbf_1 Server SQLState: 00000)~~~~WARNING (Message: drop cascades to trigger pg_trigger_2 on table master_dbo.test_tbl_trig_bbf_2 Server SQLState: 00000)~~~~WARNING (Message: drop cascades to trigger pg_trigger_4 on table master_dbo.test_tbl_trig_bbf_4 Server SQLState: 00000)~~ + + +drop table master_dbo.psql_tbl_1; +drop table master_dbo.psql_tbl_2; +GO + +-- tsql +drop table test_tbl_trig_bbf_1; +drop table test_tbl_trig_bbf_2; +drop table test_tbl_trig_bbf_3; +drop table test_tbl_trig_bbf_4; +GO diff --git a/test/JDBC/expected/TestTvp.out b/test/JDBC/expected/TestTvp.out new file mode 100644 index 0000000000..91df4b3de2 --- /dev/null +++ b/test/JDBC/expected/TestTvp.out @@ -0,0 +1,20 @@ +create type tableType as table (a int, b smallint) +create type table_variable_vu_type as table (a text not null, b int primary key, c int, d int) +create proc table_variable_vu_proc1 (@x table_variable_vu_type readonly) as begin select tvp.b from @x tvp end +prepst#!#Select * from ? #!#tvp|-|tableType|-|utils/tvp-dotnet.csv|-|utils/tvp-dotnet.csv +~~START~~ +int#!#smallint +1#!#1 +~~END~~ + +declare @var1 table_variable_vu_type insert into @var1 values ('1', 2, 3, 4) exec sp_executesql N'EXEC table_variable_vu_proc1 @x = @p0', N'@p0 table_variable_vu_type readonly', @p0=@var1 +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +drop procedure table_variable_vu_proc1; +drop type table_variable_vu_type; +drop type tableType; diff --git a/test/JDBC/expected/TestXML.out b/test/JDBC/expected/TestXML.out index dc7168f245..1c68f4a9b0 100644 --- a/test/JDBC/expected/TestXML.out +++ b/test/JDBC/expected/TestXML.out @@ -27,3 +27,28 @@ xml ~~END~~ DROP TABLE XML_dt; + +CREATE TABLE [dbo].[notification_definition]([id] [bigint] NOT NULL,[name_tx] [nvarchar](200) NOT NULL,[description_tx] [nvarchar](max) NULL,[schedule_xml] [xml] NULL,[default_sender_tx] [nvarchar](200) NULL,[lock_id] [tinyint] NOT NULL,[settings_xml] [xml] NULL,[agency_id] [bigint] NULL) +INSERT [dbo].[NOTIFICATION_DEFINITION] VALUES (13, N'INTRA_MSG', N'Intra-System Message', NULL, N'donotreply_OPMQA@ospreycompliancesuite.com', 63,N'NTF_SUB_INTRA_MSGNTF_MSG_INTRA_MSGPolicyDocumentTemplateVars11', 1) +~~ROW COUNT: 1~~ + +SELECT ID,NAME_TX,LOCK_ID,DESCRIPTION_TX,N'' as emptystring, SCHEDULE_XML,DEFAULT_SENDER_TX,SETTINGS_XML,AGENCY_ID FROM NOTIFICATION_DEFINITION +~~START~~ +bigint#!#nvarchar#!#tinyint#!#nvarchar#!#nvarchar#!#xml#!#nvarchar#!#xml#!#bigint +13#!#INTRA_MSG#!#63#!#Intra-System Message#!##!##!#donotreply_OPMQA@ospreycompliancesuite.com#!#NTF_SUB_INTRA_MSGNTF_MSG_INTRA_MSGPolicyDocumentTemplateVars11#!#1 +~~END~~ + +DROP TABLE [dbo].[notification_definition]; + +CREATE TABLE [dbo].[notification_definition]([id] [bigint] NOT NULL,[name_tx] [nvarchar](200) NOT NULL,[description_tx] [nvarchar](max) NULL,[schedule_xml] [xml] NULL,[default_sender_tx] [nvarchar](200) NULL,[lock_id] [tinyint] NOT NULL,[settings_xml] [xml] NULL,[agency_id] [bigint] NULL) +prepst#!# INSERT [dbo].[NOTIFICATION_DEFINITION] VALUES(?, ?, ?, ?, ?, ?, ?, ?) #!#bigint|-|a|-|13#!#nvarchar|-|b|-|INTRA_MSG#!#nvarchar|-|c|-|Intra-System Message#!#XML|-|d|-|NULL#!#nvarchar|-|e|-|donotreply_OPMQA#!#tinyint|-|f|-|63#!#XML|-|g|-|NTF_SUB_INTRA_MSGNTF_MSG_INTRA_MSGPolicyDocumentTemplateVars11#!#bigint|-|h|-|1 +~~ROW COUNT: 1~~ + +#INSERT [dbo].[NOTIFICATION_DEFINITION] VALUES (13, N'INTRA_MSG', N'Intra-System Message', NULL, N'donotreply_OPMQA@ospreycompliancesuite.com', 63,N'NTF_SUB_INTRA_MSGNTF_MSG_INTRA_MSGPolicyDocumentTemplateVars11', 1) +SELECT ID,NAME_TX,LOCK_ID,DESCRIPTION_TX,N'' as emptystring, SCHEDULE_XML,DEFAULT_SENDER_TX,SETTINGS_XML,AGENCY_ID FROM NOTIFICATION_DEFINITION +~~START~~ +bigint#!#nvarchar#!#tinyint#!#nvarchar#!#nvarchar#!#xml#!#nvarchar#!#xml#!#bigint +13#!#INTRA_MSG#!#63#!#Intra-System Message#!##!#NULL#!#donotreply_OPMQA#!#NTF_SUB_INTRA_MSGNTF_MSG_INTRA_MSGPolicyDocumentTemplateVars11#!#1 +~~END~~ + +DROP TABLE [dbo].[notification_definition]; diff --git a/test/JDBC/expected/Test_ISNULL-vu-cleanup.out b/test/JDBC/expected/Test_ISNULL-vu-cleanup.out new file mode 100644 index 0000000000..c552cd10bc --- /dev/null +++ b/test/JDBC/expected/Test_ISNULL-vu-cleanup.out @@ -0,0 +1,35 @@ +DROP FUNCTION [dbo].[test_isnull_func1]; +GO + +DROP FUNCTION [dbo].[test_isnull_func2]; +GO + +DROP PROCEDURE [dbo].[test_isnull_proc1]; +GO + +DROP VIEW [dbo].[test_isnull_view] +GO + +DROP VIEW [dbo].[test_isnull_view1] +GO + +DROP VIEW [dbo].[test_isnull_view2] +GO + +DROP VIEW [dbo].[test_isnull_view3] +GO + +DROP VIEW [dbo].[test_isnull_view4] +GO + +DROP VIEW [dbo].[test_isnull_view5] +GO + +DROP VIEW [dbo].[test_isnull_view6] +GO + +DROP VIEW [dbo].[test_isnull_view7] +GO + +DROP TABLE [dbo].[test_isnull_table] +GO diff --git a/test/JDBC/expected/Test_ISNULL-vu-prepare.out b/test/JDBC/expected/Test_ISNULL-vu-prepare.out new file mode 100644 index 0000000000..e7748ace28 --- /dev/null +++ b/test/JDBC/expected/Test_ISNULL-vu-prepare.out @@ -0,0 +1,72 @@ +CREATE TABLE [dbo].[test_isnull_table]( + [id] [bigint] IDENTITY(1,1) NOT NULL, + [my_varchar_data] [varchar](20) NULL, + [my_computed_column] AS isnull([my_varchar_data],[id])) +GO + +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES ('1') +INSERT INTO [dbo].[test_isnull_table]([my_varchar_data])VALUES (NULL) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create view [dbo].[test_isnull_view] as select isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view1] as select * from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO + +create view [dbo].[test_isnull_view2] as select * from [dbo].[test_isnull_table] where isnull(NULL,[id]) = 1; +GO + +create view [dbo].[test_isnull_view3] as +select ISNULL(NULL, NULL); +GO + +create view [dbo].[test_isnull_view4] as +select ISNULL(NULL, 'Unassigned'); +GO + +create view [dbo].[test_isnull_view5] as +select + ISNULL([my_varchar_data], 'Unassigned') +from [dbo].[test_isnull_table]; +GO + +create view [dbo].[test_isnull_view6] as +select ISNULL('Unassigned', 1); +GO + +create view [dbo].[test_isnull_view7] as +select ISNULL ('', 5); +GO + +CREATE FUNCTION [dbo].[test_isnull_func1]() +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT + SELECT @ans= isnull([my_varchar_data],[id]) from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1 + RETURN @ans +END +GO + +CREATE FUNCTION [dbo].[test_isnull_func2](@in1 varchar(20), @in2 bigint) +RETURNS BIGINT AS +BEGIN + DECLARE @ans BIGINT = isnull(@in1, @in2) + RETURN @ans +END +GO + +CREATE PROCEDURE [dbo].[test_isnull_proc1] +AS +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table] where isnull([my_varchar_data],[id]) = 1; +GO diff --git a/test/JDBC/expected/Test_ISNULL-vu-verify.out b/test/JDBC/expected/Test_ISNULL-vu-verify.out new file mode 100644 index 0000000000..09b1ca40ab --- /dev/null +++ b/test/JDBC/expected/Test_ISNULL-vu-verify.out @@ -0,0 +1,204 @@ +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + name = 'my_computed_column' and + object_id = + ( + select object_id from sys.tables where name = 'test_isnull_table' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select * from [dbo].[test_isnull_table] +GO +~~START~~ +bigint#!#varchar#!#varchar +1#!#1#!#1 +2#!##!#2 +~~END~~ + + +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +#!#Unassigned#!#Unassigned#!#Unassigned#!# +~~END~~ + + +select * from [dbo].[test_isnull_view]; +GO +~~START~~ +varchar +1 +2 +~~END~~ + + +select * from [dbo].[test_isnull_view1]; +GO +~~START~~ +bigint#!#varchar#!#varchar +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view2]; +GO +~~START~~ +bigint#!#varchar#!#varchar +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view3]; +GO +~~START~~ +int + +~~END~~ + + +select * from [dbo].[test_isnull_view4]; +GO +~~START~~ +varchar +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view5]; +GO +~~START~~ +varchar +1 +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view6]; +GO +~~START~~ +varchar +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view7]; +GO +~~START~~ +varchar + +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view3' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view4' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view5' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view6' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view7' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select [dbo].[test_isnull_func1](); +GO +~~START~~ +bigint +1 +~~END~~ + + +select [dbo].[test_isnull_func2]('1', 1); +GO +~~START~~ +bigint +1 +~~END~~ + + +exec [dbo].[test_isnull_proc1]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +~~END~~ + diff --git a/test/JDBC/expected/Test_list_of_sys_catalog_present_in_dbo.out b/test/JDBC/expected/Test_list_of_sys_catalog_present_in_dbo.out new file mode 100644 index 0000000000..d90fbbe99b --- /dev/null +++ b/test/JDBC/expected/Test_list_of_sys_catalog_present_in_dbo.out @@ -0,0 +1,66 @@ +-- This test file fails only in case of new implementation of sys.sys% catalog view +-- which was present only in 'sys' schema but not in 'dbo' schema. +-- If observed the T-SQL behaviour these sys.sys% catalog views are present in +-- both 'sys' and 'dbo' schema. +-- To pass this test, follow the steps: +-- 1. Go to function set_schemaname_dbo_to_sys present in (babelfish_extensions/contrib/babelfish_tsql/src/multidb.c) +-- 2. After checking the behaviour, Add the sys% catalog view name to the list present in function +-- 3. Finally remove the sys% view name in the table list_of_view_should_be_present_in_dbo_table +-- 4. Add tests for the dbo.sys%(which should be behaving same as sys.sys%) in the respective test file +CREATE TABLE list_of_view_should_be_present_in_dbo_table(view_name varchar(100)); +GO + +INSERT INTO list_of_view_should_be_present_in_dbo_table values + ('syscacheobjects'), + ('syscomments'), + ('sysconstraints'), + ('sysdepends'), + ('sysdevices'), + ('sysfilegroups'), + ('sysfiles'), + ('sysfulltextcatalogs'), + ('sysindexkeys'), + ('syslockinfo'), + ('sysmembers'), + ('sysmessages'), + ('sysoledbusers'), + ('sysperfinfo'), + ('syspermissions'), + ('sysprotects'), + ('sysreferences'), + ('sysremotelogins'), + ('sysservers'); +go +~~ROW COUNT: 19~~ + + +CREATE FUNCTION test_list_of_sys_catalog_present_in_dbo_func() +RETURNS @tab TABLE (name varchar(100)) +AS +BEGIN +DECLARE @a varchar(100); +DECLARE cur CURSOR FOR SELECT * FROM list_of_view_should_be_present_in_dbo_table; +OPEN cur; +WHILE @@FETCH_STATUS = 0 + BEGIN + FETCH NEXT FROM cur INTO @a; + IF OBJECT_ID(('sys.' + @a ), 'V') IS NOT NULL + INSERT INTO @tab VALUES (cast(@a as varchar(100))); + END +CLOSE cur; +DEALLOCATE cur; +END +GO + +select * from test_list_of_sys_catalog_present_in_dbo_func(); +go +~~START~~ +varchar +~~END~~ + + +DROP TABLE list_of_view_should_be_present_in_dbo_table; +GO + +DROP FUNCTION test_list_of_sys_catalog_present_in_dbo_func; +GO diff --git a/test/JDBC/expected/Test_user_from_win_login-vu-verify.out b/test/JDBC/expected/Test_user_from_win_login-vu-verify.out index da05e59e00..4999580297 100644 --- a/test/JDBC/expected/Test_user_from_win_login-vu-verify.out +++ b/test/JDBC/expected/Test_user_from_win_login-vu-verify.out @@ -10,10 +10,48 @@ admin@PNQ ~~END~~ +exec babelfish_add_domain_mapping_entry 'CORP', 'CORP.EXAMPLE.COM'; +GO + +create login [CORP\logina4038] from windows; +GO + +create login [corp\loginb4038] from windows; +GO + +select rolname from sys.babelfish_authid_login_ext where rolname like '%4038%' order by 1; +GO +~~START~~ +varchar +logina4038@CORP.EXAMPLE.COM +loginb4038@CORP.EXAMPLE.COM +~~END~~ + + +create user usera4038 for login [corp\logina4038]; +GO + +create user userb4038 for login [CORP\loginb4038]; +GO + +drop user usera4038; +GO + +drop user userb4038; +GO + +drop login [corp\logina4038]; +GO + +drop login [corp\loginb4038]; +GO + +exec babelfish_remove_domain_mapping_entry 'CORP'; +GO + drop user win_admin; GO drop login [pnq\admin]; GO - diff --git a/test/JDBC/expected/alter_authorization_change_db_owner-vu-verify.out b/test/JDBC/expected/alter_authorization_change_db_owner-vu-verify.out new file mode 100644 index 0000000000..e7454698da --- /dev/null +++ b/test/JDBC/expected/alter_authorization_change_db_owner-vu-verify.out @@ -0,0 +1,701 @@ +-- tsql +create login dba_login with password='12345678' +go +create login new_OWNER_login with password='12345678' +go +create login new_owner_login2 with password='12345678' +go +alter server role sysadmin add member dba_login +go + +-- tsql user=dba_login password=12345678 +-- end preparation +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dba_login#!#master +~~END~~ + +create database change_owner_db +go +alter authorization on database::no_such_db_chgownerdb to new_owner_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the database 'no_such_db_chgownerdb', because it does not exist or you do not have permission.)~~ + +alter authorization on database::change_owner_db to no_such_login_chgownerdb +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'no_such_login_chgownerdb', because it does not exist or you do not have permission.)~~ + + +-- system databases not allowed +alter authorization on database::master to new_owner_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot change the owner of the master, model, tempdb or distribution database.)~~ + +alter authorization on database::tempdb to new_owner_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot change the owner of the master, model, tempdb or distribution database.)~~ + +-- allowed for msdb +alter authorization on database::msdb to new_owner_login +go +select name, suser_sname(sid) from sysdatabases where name = 'msdb' +go +~~START~~ +text#!#nvarchar +msdb#!#new_OWNER_login +~~END~~ + + +-- tsql +use master +go +declare @cmd varchar(100) +set @cmd = 'alter authorization on database::msdb to ' + suser_name() +execute(@cmd) +go + +-- tsql user=dba_login password=12345678 +-- before owner change: +select name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +text#!#nvarchar +change_owner_db#!#dba_login +~~END~~ + +ALTER authorization on database::change_owner_db to new_owner_login +go +-- after owner change: +select name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +text#!#nvarchar +change_owner_db#!#new_OWNER_login +~~END~~ + + +-- change back to current user +alter AUTHORIZATION on database::change_owner_db to dba_login +go +select name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +text#!#nvarchar +change_owner_db#!#dba_login +~~END~~ + + +-- grant ownership to new owner and verify access +-- grant multiple times +alter authorization on DATABASE::change_owner_db to new_owner_LOGIN +go +alter authorization on database::change_owner_db TO new_owner_login +go +alter authorization on database::change_owner_db to new_owner_login +go + +-- tsql user=new_owner_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +new_OWNER_login#!#master +~~END~~ + +use change_owner_db +go +select user_name() +go +~~START~~ +nvarchar +dbo +~~END~~ + +create table t(a int) +insert t values(123) +go +~~ROW COUNT: 1~~ + + +-- tsql user=dba_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dba_login#!#master +~~END~~ + +alter authorization on database::change_owner_db to dba_login +go + +-- tsql user=new_owner_login password=12345678 +-- previous owner is still in the DB and should still have access despite no longer being the owner +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +new_OWNER_login#!#change_owner_db +~~END~~ + +select * from t +go +~~START~~ +int +123 +~~END~~ + +create table t2(a int) +go + +-- but previous owner should loose access after moving out of the DB +use master +go +use change_owner_db +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server principal "new_owner_login" is not able to access the database "change_owner_db" under the current security context)~~ + + +-- tsql user=dba_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dba_login#!#master +~~END~~ + +-- when new owner has guest access before change, granting ownership is allowed +use master +go +drop database change_owner_db +go +create database CHANGE_OWNER_DB +go +use change_OWNER_db +go +grant connect to guest +go +alter authorization on database::CHANGE_owner_db to NEW_owner_login +go +select name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +text#!#nvarchar +change_owner_db#!#new_OWNER_login +~~END~~ + + +-- tsql user=new_owner_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +new_OWNER_login#!#master +~~END~~ + +use change_owner_db +go +select user_name() +go +~~START~~ +nvarchar +dbo +~~END~~ + +create table t(a int) +go +use master +go + +-- tsql user=dba_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dba_login#!#change_owner_db +~~END~~ + +-- when new owner is already a DB user, granting ownership is not allowed +use master +go +drop database change_owner_db +go +create database change_owner_db +go +use change_owner_db +go +create user new_owner_login +go +create user another_user for login new_owner_login2 +go + +-- should raise error +alter authorization on database::change_owner_db to new_owner_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The proposed new database owner is already a user or aliased in the database.)~~ + +select name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +text#!#nvarchar +change_owner_db#!#dba_login +~~END~~ + + +-- should raise error +alter authorization on database::change_owner_db to new_owner_login2 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The proposed new database owner is already a user or aliased in the database.)~~ + +select name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +text#!#nvarchar +change_owner_db#!#dba_login +~~END~~ + + +-- tsql user=dba_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dba_login#!#change_owner_db +~~END~~ + +use master +go +drop database change_owner_db +go +create database change_owner_db +go +create procedure p_change_db_owner_1 +as +begin + select 'p_change_db_owner_1: before owner change', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' + alter authorization on database::change_owner_db to new_owner_login + select 'p_change_db_owner_1: after owner change', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +end +go +exec p_change_db_owner_1 +go +~~START~~ +varchar#!#text#!#nvarchar +p_change_db_owner_1: before owner change#!#change_owner_db#!#dba_login +~~END~~ + +~~START~~ +varchar#!#text#!#nvarchar +p_change_db_owner_1: after owner change#!#change_owner_db#!#new_OWNER_login +~~END~~ + + +-- tsql user=dba_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dba_login#!#master +~~END~~ + +use master +go +alter authorization on database::change_owner_db to dba_login +go +create procedure p_change_db_owner_2 +@dbname nvarchar(50), +@owner nvarchar(50) +as +begin + declare @cmd nvarchar(100) + set @cmd = 'alter authorization on database::' + @dbname + ' to ' + @owner + select @cmd + select 'p_change_db_owner_2: before owner change', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' + execute(@cmd) + select 'p_change_db_owner_2: after owner change', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +end +go +exec p_change_db_owner_2 change_owner_db, new_owner_login +go +~~START~~ +nvarchar +alter authorization on database::change_owner_db to new_owner_login +~~END~~ + +~~START~~ +varchar#!#text#!#nvarchar +p_change_db_owner_2: before owner change#!#change_owner_db#!#dba_login +~~END~~ + +~~START~~ +varchar#!#text#!#nvarchar +p_change_db_owner_2: after owner change#!#change_owner_db#!#new_OWNER_login +~~END~~ + + +-- tsql user=new_owner_login password=12345678 +select suser_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +new_OWNER_login#!#master +~~END~~ + +use change_owner_db +go +select user_name(), suser_name() +go +~~START~~ +nvarchar#!#nvarchar +dbo#!#new_OWNER_login +~~END~~ + + +-- can grant to yourself when you're owner already (but it's a noop) +alter authorization on database::change_owner_db to new_owner_login +go + +-- cannot grant to another owner without sysadmin role, even when you're the owner already +alter authorization on database::change_owner_db to new_owner_login2 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'new_owner_login2', because it does not exist or you do not have permission.)~~ + + +-- ... not even to a sysadmin role login +alter authorization on database::change_owner_db to dba_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot find the principal 'dba_login', because it does not exist or you do not have permission.)~~ + + +use master +go + +-- cannot rename the database without sysadmin role, even when you're the owner already +-- ALTER DATABASE is not yet supported in Babelfish: +alter database change_owner_db modify name = change_owner_db_renamed +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER DATABASE' is not currently supported in Babelfish)~~ + + +-- cannot rename the database without sysadmin role, even when you're the owner already +-- sp_rename not yet supported for 'database' type in Babelfish: +sp_rename 'change_owner_db', 'change_owner_db_renamed', 'database' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Provided @objtype is not currently supported in Babelfish)~~ + + +-- tsql user=dba_login password=12345678 +-- roll back owner change in transaction +use master +go +alter authorization on database::change_owner_db to dba_login +go +begin tran +go +select 'before owner change', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +varchar#!#text#!#nvarchar +before owner change#!#change_owner_db#!#dba_login +~~END~~ + +alter authorization on database::change_owner_db to new_owner_login +go +select 'after owner change', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +varchar#!#text#!#nvarchar +after owner change#!#change_owner_db#!#new_OWNER_login +~~END~~ + +rollback +go +select 'after rollback', name, suser_sname(sid) from sysdatabases where name = 'change_owner_db' +go +~~START~~ +varchar#!#text#!#nvarchar +after rollback#!#change_owner_db#!#dba_login +~~END~~ + + +use master +go +-- non-sysadmin owner can drop database +drop database change_owner_db +go +-- should return NULL +select db_id('change_owner_db') +go +~~START~~ +smallint + +~~END~~ + + +-- tests for long names and mixed case +create database DB63long_012345678901234567890123456789012345678901234567890123 +go +create login LOGIN63long_345678901234567890123456789012345678901234567890123 with password = '12345678' +go +alter authorization on database::DB63long_012345678901234567890123456789012345678901234567890123 to LOGIN63long_345678901234567890123456789012345678901234567890123 +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB63LONG%' +go +~~START~~ +text#!#nvarchar +db63long_012345678901234567890123456789012345678901234567890123#!#LOGIN63long_345678901234567890123456789012345678901234567890123 +~~END~~ + +alter authorization on database::[DB63long_012345678901234567890123456789012345678901234567890123] to dba_login +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB63LONG%' +go +~~START~~ +text#!#nvarchar +db63long_012345678901234567890123456789012345678901234567890123#!#dba_login +~~END~~ + +alter authorization on database::[DB63long_012345678901234567890123456789012345678901234567890123] to [LOGIN63long_345678901234567890123456789012345678901234567890123] +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB63LONG%' +go +~~START~~ +text#!#nvarchar +db63long_012345678901234567890123456789012345678901234567890123#!#LOGIN63long_345678901234567890123456789012345678901234567890123 +~~END~~ + +set quoted_identifier on +go +alter authorization on database::"DB63long_012345678901234567890123456789012345678901234567890123" to dba_login +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB63LONG%' +go +~~START~~ +text#!#nvarchar +db63long_012345678901234567890123456789012345678901234567890123#!#dba_login +~~END~~ + +alter authorization on database::"DB63long_012345678901234567890123456789012345678901234567890123" to "LOGIN63long_345678901234567890123456789012345678901234567890123" +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB63LONG%' +go +~~START~~ +text#!#nvarchar +db63long_012345678901234567890123456789012345678901234567890123#!#LOGIN63long_345678901234567890123456789012345678901234567890123 +~~END~~ + +set quoted_identifier off +go + +-- tsql user=LOGIN63long_345678901234567890123456789012345678901234567890123 password=12345678 +use DB63long_012345678901234567890123456789012345678901234567890123 +go +select user_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dbo#!#db63long_012345678901234567890123456789012345678901234567890123 +~~END~~ + +use master +go +drop database DB63long_012345678901234567890123456789012345678901234567890123 +go + +-- tsql user=dba_login password=12345678 +create database DB64long_0123456789012345678901234567890123456789012345678901234 +go +create login LOGIN64long_3456789012345678901234567890123456789012345678901234 with password = '12345678' +go +alter authorization on database::DB64long_0123456789012345678901234567890123456789012345678901234 to LOGIN64long_3456789012345678901234567890123456789012345678901234 +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB64LONG%' +go +~~START~~ +text#!#nvarchar +db64long_012345678901234567890109e0da63a1cdb0673c21e39afa6178e9#!#LOGIN64long_3456789012345678901234567890123456789012345678901234 +~~END~~ + +alter authorization on database::[DB64long_0123456789012345678901234567890123456789012345678901234] to dba_login +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB64LONG%' +go +~~START~~ +text#!#nvarchar +db64long_012345678901234567890109e0da63a1cdb0673c21e39afa6178e9#!#dba_login +~~END~~ + +alter authorization on database::[DB64long_0123456789012345678901234567890123456789012345678901234] to [LOGIN64long_3456789012345678901234567890123456789012345678901234] +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB64LONG%' +go +~~START~~ +text#!#nvarchar +db64long_012345678901234567890109e0da63a1cdb0673c21e39afa6178e9#!#LOGIN64long_3456789012345678901234567890123456789012345678901234 +~~END~~ + +set quoted_identifier on +go +alter authorization on database::"DB64long_0123456789012345678901234567890123456789012345678901234" to dba_login +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB64LONG%' +go +~~START~~ +text#!#nvarchar +db64long_012345678901234567890109e0da63a1cdb0673c21e39afa6178e9#!#dba_login +~~END~~ + +alter authorization on DATABASE::"DB64long_0123456789012345678901234567890123456789012345678901234" to "LOGIN64long_3456789012345678901234567890123456789012345678901234" +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB64LONG%' +go +~~START~~ +text#!#nvarchar +db64long_012345678901234567890109e0da63a1cdb0673c21e39afa6178e9#!#LOGIN64long_3456789012345678901234567890123456789012345678901234 +~~END~~ + +set quoted_identifier off +go + + +-- tsql +-- this connection will fail as it is currently not possible to connect to Babelfish with a login name longer than 63 characters +-- commented out this test since the error message in the Github JDBC tests is different from that in the locally executed JDBC tests +-- commented out: tsql user=LOGIN64long_3456789012345678901234567890123456789012345678901234 password=12345678 +-- error msg in local JDBC tests: ~~ERROR (Code: 33557097)~~, -~~ERROR (Message: role "login64long_345678901234567890123456789012345678901234567890123" does not exist )~~ +-- error msg in Github JDBC tests: ~~ERROR (Code: 18456)~~, ~~ERROR (Message: Login failed for user "login64long_3456789012345678901234567890123456789012345678901234" )~~ +-- use DB64long_0123456789012345678901234567890123456789012345678901234 +-- go +-- select user_name(), db_name() +-- go +-- use master +-- go +use master +go +drop database DB64long_0123456789012345678901234567890123456789012345678901234 +go + +-- other ALTER AUTHORIZATION variants, not supported +alter authorization on database::mydb TO public +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'public' at line 2 and character position 41)~~ + +alter authorization on database::mydb to schema owner +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER AUTHORIZATION TO SCHEMA OWNER' is not currently supported in Babelfish)~~ + +alter AUTHORIZATION on mydb to dba_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER AUTHORIZATION on object types other than DATABASE::' is not currently supported in Babelfish)~~ + +alter AUTHORIZATION on table::mydb to dba_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER AUTHORIZATION on object types other than DATABASE::' is not currently supported in Babelfish)~~ + +ALTER authorization on database::my.data.base to dba_login +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER AUTHORIZATION with multi-part database name' is not currently supported in Babelfish)~~ + +create procedure p_change_db_owner_3 +as + alter authorization on database::mydb to schema owner +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER AUTHORIZATION TO SCHEMA OWNER' is not currently supported in Babelfish)~~ + +declare @cmd varchar(100) = 'alter authorization on database::mydb to schema owner' +execute(@cmd) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'ALTER AUTHORIZATION TO SCHEMA OWNER' is not currently supported in Babelfish)~~ + + + +-- tsql +-- cleanup +use master +go +set nocount on +go +-- kill remaining sessions +create table #killed(killed int) +go +declare @spid int, @cmd varchar(30) +while (1=1) +begin +select @spid = spid from sys.sysprocesses where spid <> @@spid and spid not in (select killed from #killed) +and (lower(loginname) like 'new_owner_login%' or lower(loginname) like 'login6%' or lower(loginname) = 'dba_login') +if @@rowcount = 0 break +insert #killed values(@spid) +set @cmd = 'kill ' + convert(varchar, @spid) +execute(@cmd) +end +go +exec pg_sleep 3 +go + +use master +go +-- database is expected to have been dropped by the owner, so expecting an error msg here: +drop database change_owner_db +go +~~ERROR (Code: 911)~~ + +~~ERROR (Message: database "change_owner_db" does not exist)~~ + +drop login dba_login +go +drop login new_owner_login +go +drop login new_owner_login2 +go +drop login LOGIN63long_345678901234567890123456789012345678901234567890123 +go +drop login LOGIN64long_3456789012345678901234567890123456789012345678901234 +go +drop procedure p_change_db_owner_1 +go +drop procedure p_change_db_owner_2 +go +-- should raise error as procedure was not created: +drop procedure p_change_db_owner_3 +go +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: could not find a procedure named "p_change_db_owner_3")~~ + 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/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_4299.out b/test/JDBC/expected/babel_4299.out new file mode 100644 index 0000000000..585aa27688 --- /dev/null +++ b/test/JDBC/expected/babel_4299.out @@ -0,0 +1,309 @@ +select ''+'ps'; +GO +~~START~~ +varchar +ps +~~END~~ + + +select 'rs' + ''; +GO +~~START~~ +varchar +rs +~~END~~ + + +select '' + ''; +GO +~~START~~ +varchar + +~~END~~ + + +select '' + NULL; +GO +~~START~~ +varchar + +~~END~~ + + +select NULL + ''; +GO +~~START~~ +varchar + +~~END~~ + + +set quoted_identifier off +GO +select ""+'s'; +GO +~~START~~ +varchar +s +~~END~~ + + +set quoted_identifier off +GO +select 'rs' + ""; +GO +~~START~~ +varchar +rs +~~END~~ + + +set quoted_identifier off +GO +select '' + ""; +GO +~~START~~ +varchar + +~~END~~ + + +set quoted_identifier off +GO +select "" + NULL; +GO +~~START~~ +varchar + +~~END~~ + + +set quoted_identifier off +GO +select NULL + ""; +GO +~~START~~ +varchar + +~~END~~ + + +set quoted_identifier off +GO +select ""+"s"; +GO +~~START~~ +varchar +s +~~END~~ + + +set quoted_identifier off +GO +select "pr" + ""; +GO +~~START~~ +varchar +pr +~~END~~ + + +set quoted_identifier off +GO +select "" + ""; +GO +~~START~~ +varchar + +~~END~~ + + +set quoted_identifier off +GO +select "" + ""; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT 'Hello' + NULL + 'World'; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT 'Hello' + NULL + 'World'; +GO +~~START~~ +varchar +HelloWorld +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT '' + NULL + 'World'; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT '' + NULL + 'World'; +GO +~~START~~ +varchar +World +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT '' + NULL + ''; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT '' + NULL + ''; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT NULL + 'World'; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT NULL + 'World'; +GO +~~START~~ +varchar +World +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT 'Hello' + NULL; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT 'Hello' + NULL; +GO +~~START~~ +varchar +Hello +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT "" + NULL + 'World'; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT "" + NULL + 'World'; +GO +~~START~~ +varchar +World +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT "" + NULL + ""; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT "" + NULL + ""; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT '' + NULL + "World"; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT '' + NULL + "World"; +GO +~~START~~ +varchar +World +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL ON; +GO +SELECT '' + NULL + ""; +GO +~~START~~ +varchar + +~~END~~ + + +SET CONCAT_NULL_YIELDS_NULL OFF; +GO +SELECT '' + NULL + ""; +GO +~~START~~ +varchar + +~~END~~ + diff --git a/test/JDBC/expected/babel_collection.out b/test/JDBC/expected/babel_collection.out new file mode 100644 index 0000000000..4c8bb3625c --- /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..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* '\%ones'::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~~ + + +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..32.78 rows=1 width=32) + Filter: (((c1)::text ~~* '\_ones'::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~~ + + +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~~ +nvarchar +ä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_context_info-vu-cleanup.out b/test/JDBC/expected/babel_context_info-vu-cleanup.out new file mode 100644 index 0000000000..6588449608 --- /dev/null +++ b/test/JDBC/expected/babel_context_info-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP PROCEDURE BABEL_SET_CONTEXT_INFO +GO + +DROP PROCEDURE BABEL_GET_CONTEXT_INFO_WITH_PLP +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..43c3f26ae6 --- /dev/null +++ b/test/JDBC/expected/babel_context_info-vu-prepare.out @@ -0,0 +1,25 @@ +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_WITH_PLP +AS +BEGIN + SELECT sys.bbf_get_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..7aed2d8f8a --- /dev/null +++ b/test/JDBC/expected/babel_context_info-vu-verify.out @@ -0,0 +1,400 @@ +-- upgrade test +SELECT CONTEXT_INFO() +GO +~~START~~ +varbinary + +~~END~~ + + +EXEC BABEL_GET_CONTEXT_INFO_WITH_PLP +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_WITH_PLP +GO +~~START~~ +varbinary +1234567812345678000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +~~END~~ + + +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, which should return error +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~~ + + +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 +~~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/expected/babel_cursor.out b/test/JDBC/expected/babel_cursor.out index d365073db3..6db712a821 100644 --- a/test/JDBC/expected/babel_cursor.out +++ b/test/JDBC/expected/babel_cursor.out @@ -17,14 +17,16 @@ GO -CREATE PROCEDURE babel_fetch_cursor_helper_int_proc(@cur CURSOR, @num_fetch int) +CREATE PROCEDURE babel_cursor_proc(@num_fetch int) AS BEGIN DECLARE @var_i int; DECLARE @cnt int = 0; + DECLARE cur CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i + OPEN cur WHILE @cnt < @num_fetch BEGIN - FETCH FROM @cur INTO @var_i + FETCH FROM cur INTO @var_i SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) IF @@FETCH_STATUS <> 0 BREAK @@ -33,114 +35,12 @@ BEGIN SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) SET @cnt = @cnt + 1 END + + CLOSE cur END; GO - -CREATE PROCEDURE babel_fetch_cursor_helper_char_proc(@cur CURSOR, @num_fetch int) -AS -BEGIN - DECLARE @var_c varchar(100); - DECLARE @cnt int = 0; - WHILE @cnt < @num_fetch - BEGIN - FETCH FROM @cur INTO @var_c - SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) - IF @@FETCH_STATUS <> 0 - BREAK - SELECT '@var_c: ' + CAST(@var_c AS VARCHAR(100)) - IF (@var_c IS NULL) - SELECT '@var_c is null: ' + CAST((case when @var_c is null then 'true' else 'false' end) AS VARCHAR(100)) - SET @cnt = @cnt + 1 - END -END; -GO - - - -CREATE PROCEDURE babel_cursor_proc -AS -BEGIN - DECLARE @var_a int; - DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; - OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; - CLOSE cur_a; -END; -GO - -EXEC babel_cursor_proc; -GO -~~START~~ -varchar -@@fetch_status: 0 -~~END~~ - -~~START~~ -varchar - -~~END~~ - -~~START~~ -varchar -@var_i is null: true -~~END~~ - -~~START~~ -varchar -@@fetch_status: 0 -~~END~~ - -~~START~~ -varchar -@var_i: 1 -~~END~~ - -~~START~~ -varchar -@@fetch_status: 0 -~~END~~ - -~~START~~ -varchar -@var_i: 2 -~~END~~ - -~~START~~ -varchar -@@fetch_status: 0 -~~END~~ - -~~START~~ -varchar -@var_i: 3 -~~END~~ - -~~START~~ -varchar -@@fetch_status: 0 -~~END~~ - -~~START~~ -varchar -@var_i: 4 -~~END~~ - - - - -CREATE PROCEDURE babel_cursor_no_semi_proc -AS -BEGIN - DECLARE @var_a int - DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i - OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; - CLOSE cur_a -END; -GO - -EXEC babel_cursor_no_semi_proc; +EXEC babel_cursor_proc 5; GO ~~START~~ varchar @@ -211,8 +111,6 @@ GO ~~ERROR (Message: "cur_a" is not a known variable)~~ - - -- no cursor cur_b (in CLOSE) CREATE PROCEDURE babel_invalid_cursor_proc_2 AS @@ -221,7 +119,6 @@ BEGIN DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE cur_b; END; GO @@ -244,8 +141,6 @@ GO ~~ERROR (Message: variable "@var_a" must be of type cursor or refcursor)~~ - - -- CLOSE with non-cursor var CREATE PROCEDURE babel_invalid_cursor_proc_4 AS @@ -254,7 +149,6 @@ BEGIN DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE @var_a; END; GO @@ -281,8 +175,6 @@ GO ~~ERROR (Message: 'GLOBAL CURSOR' is not currently supported in Babelfish)~~ - - -- global cursor is not supported yet (CLOSE) CREATE PROCEDURE babel_cursor_global_close_proc AS @@ -291,7 +183,6 @@ BEGIN DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE GLOBAL cur_a; END; GO @@ -847,9 +738,20 @@ CREATE PROCEDURE babel_local_cursor_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR LOCAL FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE cur_a; END; GO @@ -868,7 +770,7 @@ varchar ~~START~~ varchar -@var_i is null: true +@var_a is null: true ~~END~~ ~~START~~ @@ -878,7 +780,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -888,7 +790,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~START~~ @@ -898,7 +800,7 @@ varchar ~~START~~ varchar -@var_i: 3 +@var_a: 3 ~~END~~ ~~START~~ @@ -908,7 +810,7 @@ varchar ~~START~~ varchar -@var_i: 4 +@var_a: 4 ~~END~~ @@ -918,9 +820,20 @@ CREATE PROCEDURE babel_forward_only_cursor_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR FORWARD_ONLY FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 3; + WHILE @cnt < 3 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END -- error FETCH PRIOR FROM cur_a INTO @var_a; SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)); @@ -943,7 +856,7 @@ varchar ~~START~~ varchar -@var_i is null: true +@var_a is null: true ~~END~~ ~~START~~ @@ -953,7 +866,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -963,7 +876,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~ERROR (Code: 33557097)~~ @@ -977,9 +890,20 @@ CREATE PROCEDURE babel_scroll_cursor_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR SCROLL FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 3; + WHILE @cnt < 3 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END FETCH PRIOR FROM cur_a INTO @var_a; SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)); SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)); @@ -1001,7 +925,7 @@ varchar ~~START~~ varchar -@var_i is null: true +@var_a is null: true ~~END~~ ~~START~~ @@ -1011,7 +935,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -1021,7 +945,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~START~~ @@ -1041,9 +965,20 @@ CREATE PROCEDURE babel_static_cursor_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR STATIC FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE cur_a; END; GO @@ -1062,7 +997,7 @@ varchar ~~START~~ varchar -@var_i is null: true +@var_a is null: true ~~END~~ ~~START~~ @@ -1072,7 +1007,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -1082,7 +1017,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~START~~ @@ -1092,7 +1027,7 @@ varchar ~~START~~ varchar -@var_i: 3 +@var_a: 3 ~~END~~ ~~START~~ @@ -1102,19 +1037,16 @@ varchar ~~START~~ varchar -@var_i: 4 +@var_a: 4 ~~END~~ - - CREATE PROCEDURE babel_keyset_cursor_proc AS BEGIN DECLARE @var_a int; DECLARE cur_a CURSOR KEYSET FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE cur_a; END; GO @@ -1124,8 +1056,6 @@ GO - - --EXEC babel_keyset_cursor_proc; --GO CREATE PROCEDURE babel_dynamic_cursor_proc @@ -1134,7 +1064,6 @@ BEGIN DECLARE @var_a int; DECLARE cur_a CURSOR DYNAMIC FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE cur_a; END; GO @@ -1152,9 +1081,20 @@ CREATE PROCEDURE babel_fast_forward_cursor_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR FAST_FORWARD FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE cur_a; END; GO @@ -1173,7 +1113,7 @@ varchar ~~START~~ varchar -@var_i is null: true +@var_a is null: true ~~END~~ ~~START~~ @@ -1183,7 +1123,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -1193,7 +1133,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~START~~ @@ -1203,7 +1143,7 @@ varchar ~~START~~ varchar -@var_i: 3 +@var_a: 3 ~~END~~ ~~START~~ @@ -1213,7 +1153,7 @@ varchar ~~START~~ varchar -@var_i: 4 +@var_a: 4 ~~END~~ @@ -1223,10 +1163,21 @@ CREATE PROCEDURE babel_read_only_cursor_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR READ_ONLY FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END -- TODO: currently READ_ONLY is ignored. read-only cursor is updatable. -- UPDATE babel_cursor_t1 SET i = i+1 WHERE CURRENT OF cur_a; CLOSE cur_a; @@ -1242,7 +1193,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -1252,7 +1203,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~START~~ @@ -1262,7 +1213,7 @@ varchar ~~START~~ varchar -@var_i: 3 +@var_a: 3 ~~END~~ ~~START~~ @@ -1272,7 +1223,7 @@ varchar ~~START~~ varchar -@var_i: 4 +@var_a: 4 ~~END~~ ~~START~~ @@ -1281,8 +1232,6 @@ varchar ~~END~~ - - CREATE PROCEDURE babel_scroll_locks_cursor_proc AS BEGIN @@ -1290,7 +1239,6 @@ BEGIN DECLARE cur_a CURSOR SCROLL_LOCKS FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE cur_a; END; GO @@ -1300,8 +1248,6 @@ GO - - --EXEC babel_scroll_locks_cursor_proc; --GO CREATE PROCEDURE babel_optimistic_cursor_proc @@ -1311,7 +1257,6 @@ BEGIN DECLARE cur_a CURSOR OPTIMISTIC FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; CLOSE cur_a; END; GO @@ -1517,10 +1462,21 @@ CREATE PROCEDURE babel_cursor_fetch_failure_proc AS BEGIN DECLARE @var_a int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN cur_a; FETCH NEXT FROM cur_a INTO @var_a; - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_a + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_a: ' + CAST(@var_a AS VARCHAR(100)) + IF (@var_a IS NULL) + SELECT '@var_a is null: ' + CAST((case when @var_a is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END SET @var_a = 1; FETCH NEXT FROM cur_a INTO @var_a; SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)); @@ -1537,7 +1493,7 @@ varchar ~~START~~ varchar -@var_i: 1 +@var_a: 1 ~~END~~ ~~START~~ @@ -1547,7 +1503,7 @@ varchar ~~START~~ varchar -@var_i: 2 +@var_a: 2 ~~END~~ ~~START~~ @@ -1557,7 +1513,7 @@ varchar ~~START~~ varchar -@var_i: 3 +@var_a: 3 ~~END~~ ~~START~~ @@ -1567,7 +1523,7 @@ varchar ~~START~~ varchar -@var_i: 4 +@var_a: 4 ~~END~~ ~~START~~ @@ -1609,15 +1565,37 @@ AS BEGIN DECLARE @var_i int; DECLARE @var_c varchar(10) + DECLARE @cnt int = 0; DECLARE @cur_a CURSOR; SET @cur_a = CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_int_proc @cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM @cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END DEALLOCATE @cur_a; -- set another cursor for the same curvar SET @cur_a = CURSOR FOR SELECT c FROM babel_cursor_t1 ORDER BY i; + SET @cnt = 0; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_char_proc @cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM @cur_a INTO @var_c + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_c: ' + CAST(@var_c AS VARCHAR(100)) + IF (@var_c IS NULL) + SELECT '@var_c is null: ' + CAST((case when @var_c is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE @cur_a; END; GO @@ -1746,15 +1724,37 @@ AS BEGIN DECLARE @var_i int; DECLARE @var_c varchar(10) + DECLARE @cnt int = 0; DECLARE @cur_a CURSOR; SET @cur_a = CURSOR FAST_FORWARD FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_int_proc @cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM @cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END DEALLOCATE @cur_a; -- set another cursor for the same curvar SET @cur_a = CURSOR SCROLL FOR SELECT c FROM babel_cursor_t1 ORDER BY c; + SET @cnt = 0; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_char_proc @cur_a, 5; + WHILE @cnt < 5 + BEGIN + FETCH FROM @cur_a INTO @var_c + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_c: ' + CAST(@var_c AS VARCHAR(100)) + IF (@var_c IS NULL) + SELECT '@var_c is null: ' + CAST((case when @var_c is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE @cur_a; END; GO @@ -1885,11 +1885,25 @@ BEGIN DECLARE @cur_a CURSOR; SET @cur_a = CURSOR FAST_FORWARD FOR SELECT i FROM babel_cursor_t1 ORDER BY i; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_int_proc @cur_a, 1; + FETCH FROM @cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS = 0 + BEGIN + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + END -- set another cursor for the same curvar without deallocate SET @cur_a = CURSOR SCROLL FOR SELECT c FROM babel_cursor_t1 ORDER BY c; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_char_proc @cur_a, 1; + FETCH FROM @cur_a INTO @var_c + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS = 0 + BEGIN + SELECT '@var_c: ' + CAST(@var_c AS VARCHAR(100)) + IF (@var_c IS NULL) + SELECT '@var_c is null: ' + CAST((case when @var_c is null then 'true' else 'false' end) AS VARCHAR(100)) + END CLOSE @cur_a; END; GO @@ -1941,7 +1955,14 @@ BEGIN -- set another cursor for the same curvar without deallocate SET @cur_a = CURSOR SCROLL FOR SELECT c FROM babel_cursor_t1; OPEN @cur_a; - EXEC babel_fetch_cursor_helper_char_proc @cur_a, 1; + FETCH FROM @cur_a INTO @var_c + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS = 0 + BEGIN + SELECT '@var_c: ' + CAST(@var_c AS VARCHAR(100)) + IF (@var_c IS NULL) + SELECT '@var_c is null: ' + CAST((case when @var_c is null then 'true' else 'false' end) AS VARCHAR(100)) + END CLOSE @cur_a; END; GO @@ -1985,7 +2006,14 @@ BEGIN SET @cur_a = CURSOR FAST_FORWARD FOR SELECT i FROM babel_cursor_t1; OPEN @cur_a; FETCH NEXT FROM @cur_a INTO @var_i; - EXEC babel_fetch_cursor_helper_int_proc @cur_a, 1; + FETCH FROM @cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS = 0 + BEGIN + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + END DEALLOCATE @cur_a; DEALLOCATE @cur_a; END; @@ -2760,15 +2788,38 @@ varchar CREATE PROCEDURE babel_cursor_redecl_proc AS BEGIN + DECLARE @var_i int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR LOCAL FOR SELECT i from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE cur_a DEALLOCATE cur_a -- redeclare with different definition DECLARE cur_a CURSOR LOCAL FOR SELECT i+100 from babel_cursor_t1 + SET @cnt = 0 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE cur_a DEALLOCATE cur_a END; @@ -2892,14 +2943,25 @@ varchar CREATE PROCEDURE babel_cursor_redecl_not_deallocd_proc_1 AS BEGIN + DECLARE @var_i int; + DECLARE @cnt int = 0; DECLARE cur_a CURSOR LOCAL FOR SELECT i from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END CLOSE cur_a -- redeclare with different definition DECLARE cur_a CURSOR LOCAL FOR SELECT i+100 from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 CLOSE cur_a END; GO @@ -2975,7 +3037,6 @@ BEGIN -- redeclare with different definition DECLARE cur_a CURSOR LOCAL FOR SELECT i+100 from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 END; GO @@ -2993,7 +3054,6 @@ BEGIN -- redeclare with different definition DECLARE cur_a CURSOR LOCAL FOR SELECT i+100 from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 END; GO @@ -3007,16 +3067,40 @@ GO CREATE PROCEDURE babel_cursor_redecl_goto_proc AS BEGIN + DECLARE @var_i int; + DECLARE @cnt int = 0; GOTO label1 label2: + SET @cnt = 0 DECLARE cur_a CURSOR LOCAL FOR SELECT i+100 from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END GOTO label3 label1: + SET @cnt = 0 DECLARE cur_a CURSOR LOCAL FOR SELECT i from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END DEALLOCATE cur_a GOTO label2 label3: @@ -3139,18 +3223,29 @@ varchar CREATE PROCEDURE babel_cursor_redecl_goto_proc_2 AS BEGIN + DECLARE @var_i int; + DECLARE @cnt int = 0; GOTO label1 label2: -- error is expected here because cur_a in label1 is not dealloc'd DECLARE cur_a CURSOR LOCAL FOR SELECT i+100 from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 DEALLOCATE cur_a GOTO label3 label1: DECLARE cur_a CURSOR LOCAL FOR SELECT i from babel_cursor_t1 OPEN cur_a - EXEC babel_fetch_cursor_helper_int_proc cur_a, 5 + WHILE @cnt < 5 + BEGIN + FETCH FROM cur_a INTO @var_i + SELECT '@@fetch_status: ' + CAST(@@fetch_status AS VARCHAR(10)) + IF @@FETCH_STATUS <> 0 + BREAK + SELECT '@var_i: ' + CAST(@var_i AS VARCHAR(100)) + IF (@var_i IS NULL) + SELECT '@var_i is null: ' + CAST((case when @var_i is null then 'true' else 'false' end) AS VARCHAR(100)) + SET @cnt = @cnt + 1 + END GOTO label2 label3: END @@ -3218,284 +3313,6 @@ varchar ~~ERROR (Message: cursor cur_a already exists)~~ - - -CREATE PROCEDURE babel_print_sp_cursor_list(@cur CURSOR) -AS -BEGIN - DECLARE @refname VARCHAR(200); - DECLARE @curname VARCHAR(200); - DECLARE @scope INT; - DECLARE @status INT; - DECLARE @model INT; - DECLARE @concurrency INT; - DECLARE @scrollable INT; - DECLARE @open_status INT; - DECLARE @cursor_rows DECIMAL(10,0); - DECLARE @fetch_status INT; - DECLARE @column_count INT; - DECLARE @row_count DECIMAL(10,0); - DECLARE @last_operation INT; - FETCH FROM @cur INTO @refname, @curname, @scope, @status, @model, @concurrency, @scrollable, @open_status, @cursor_rows, @fetch_status, @column_count, @row_count, @last_operation; - WHILE @@FETCH_STATUS = 0 - BEGIN - SELECT '(sp_cursor_list out) @refname: ' + @refname + ', @curname: ' + @curname + ', @scope: ' + cast(@scope as VARCHAR(10)) + ', @model: ' + cast(@model as varchar(10)) + ', @concurrency: ' + cast(@concurrency as varchar(10)) + ', @scrollable: ' + cast(@scrollable as varchar(10)) + ', @open_status: ' + cast(@open_status as varchar(10)) + ', @cursor_rows: ' + cast(@cursor_rows as varchar(10)) + ', @fetch_status: ' + cast(@fetch_status as varchar(10)) + ', @column_count: ' + cast(@column_count as varchar(10)) + ', @row_count: ' + cast(@row_count as varchar(10)) + ', @last_operation ' + cast(@last_operation as varchar(10)); - FETCH FROM @cur INTO @refname, @curname, @scope, @status, @model, @concurrency, @scrollable, @open_status, @cursor_rows, @fetch_status, @column_count, @row_count, @last_operation; - END - CLOSE @cur; - DEALLOCATE @cur; -END -GO - - - - - - - - - - - - - - - -CREATE PROCEDURE babel_sp_cursor_list_proc -AS -BEGIN - DECLARE @report_cur CURSOR; - DECLARE @var_a int; - DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; - DECLARE cur_b CURSOR FOR SELECT i+1 FROM babel_cursor_t1 ORDER BY i; - DECLARE @refcur_b CURSOR; - DECLARE @refcur_c CURSOR; - SELECT '== AFTER DECLARE =='; - EXEC sp_cursor_list @report_cur OUT, 1; - EXEC babel_print_sp_cursor_list @report_cur; - SET @refcur_b = cur_b; - SET @refcur_c = CURSOR FOR SELECT i+2 FROM babel_cursor_t1 ORDER BY i; - SELECT '== AFTER SET =='; - EXEC sp_cursor_list @report_cur OUT, 1; - EXEC babel_print_sp_cursor_list @report_cur; - OPEN cur_a; - OPEN @refcur_b; - OPEN @refcur_c; - SELECT '== AFTER OPEN =='; - EXEC sp_cursor_list @report_cur OUT, 1; - EXEC babel_print_sp_cursor_list @report_cur; - FETCH NEXT FROM cur_a INTO @var_a; - FETCH NEXT FROM @refcur_b INTO @var_a; - FETCH NEXT FROM @refcur_c INTO @var_a; - SELECT '== AFTER FETCH =='; - EXEC sp_cursor_list @report_cur OUT, 1; - EXEC babel_print_sp_cursor_list @report_cur; - CLOSE cur_a; - CLOSE @refcur_b; - CLOSE @refcur_c; - SELECT '== AFTER CLOSE =='; - EXEC sp_cursor_list @report_cur OUT, 1; - EXEC babel_print_sp_cursor_list @report_cur; - DEALLOCATE cur_a; - DEALLOCATE @refcur_b; - DEALLOCATE @refcur_c; - SELECT '== AFTER DEALLOCATE =='; - EXEC sp_cursor_list @report_cur OUT, 1; - EXEC babel_print_sp_cursor_list @report_cur; -END; -GO - -EXEC babel_sp_cursor_list_proc; -GO -~~START~~ -varchar -== AFTER DECLARE == -~~END~~ - -~~START~~ -varchar -(sp_cursor_list out) @refname: cur_a, @curname: cur_a, @scope: 1, @model: 1, @concurrency: 1, @scrollable: 1, @open_status: 0, @cursor_rows: 0, @fetch_status: -9, @column_count: -1, @row_count: 0, @last_operation 0 -~~END~~ - -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: cursor "" does not exist)~~ - - - - -CREATE PROCEDURE babel_sp_cursor_list_nested_proc_2 -AS -BEGIN - DECLARE @report_cur CURSOR; - DECLARE cur_a CURSOR FOR SELECT * FROM babel_cursor_t1 ORDER BY c; - OPEN cur_a; - SELECT '== in the nested proc =='; - EXEC sp_cursor_list @report_cur OUT, 3; - EXEC babel_print_sp_cursor_list @report_cur; -END; -GO - - - - - - -CREATE PROCEDURE babel_sp_cursor_list_nested_proc -AS -BEGIN - DECLARE @report_cur CURSOR; - DECLARE @var_a INT; - DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; - DECLARE @refcur_a CURSOR; - SET @refcur_a = cur_a; - OPEN cur_a; - FETCH NEXT FROM @refcur_a INTO @var_a; - SELECT '== before calling nested proc =='; - EXEC sp_cursor_list @report_cur OUT, 3; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC babel_sp_cursor_list_nested_proc_2; - SELECT '== after calling nested proc =='; - EXEC sp_cursor_list @report_cur OUT, 3; - EXEC babel_print_sp_cursor_list @report_cur; -END; -GO - -EXEC babel_sp_cursor_list_nested_proc; -GO -~~START~~ -varchar -== before calling nested proc == -~~END~~ - -~~START~~ -varchar -(sp_cursor_list out) @refname: cur_a, @curname: cur_a, @scope: 1, @model: 1, @concurrency: 1, @scrollable: 1, @open_status: 1, @cursor_rows: -1, @fetch_status: 0, @column_count: 1, @row_count: 1, @last_operation 2 -~~END~~ - -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: cursor "" does not exist)~~ - - - - - - - - - - - - - - - - - -CREATE PROCEDURE babel_sp_describe_cursor_proc -AS -BEGIN - DECLARE @report_cur CURSOR; - DECLARE @var_a int; - DECLARE cur_a CURSOR FOR SELECT i FROM babel_cursor_t1 ORDER BY i; - DECLARE cur_b CURSOR FOR SELECT i+1 FROM babel_cursor_t1 ORDER BY i; - DECLARE @refcur_b CURSOR; - DECLARE @refcur_c CURSOR; - SELECT '== AFTER DECLARE =='; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - SET @refcur_b = cur_b; - SET @refcur_c = CURSOR FOR SELECT i+2 FROM babel_cursor_t1 ORDER BY i; - SELECT '== AFTER SET =='; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_c'; - EXEC babel_print_sp_cursor_list @report_cur; - OPEN cur_a; - OPEN @refcur_b; - OPEN @refcur_c; - SELECT '== AFTER OPEN =='; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_c'; - EXEC babel_print_sp_cursor_list @report_cur; - FETCH NEXT FROM cur_a INTO @var_a; - FETCH NEXT FROM @refcur_b INTO @var_a; - FETCH NEXT FROM @refcur_c INTO @var_a; - SELECT '== AFTER FETCH =='; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_c'; - EXEC babel_print_sp_cursor_list @report_cur; - SELECT '== BEGIN (call with invalid argument) ==' - EXEC sp_describe_cursor @report_cur OUT, 'variable', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', '@refcur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', '@refcur_not_exsits'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_not_exsits'; - EXEC babel_print_sp_cursor_list @report_cur; - SELECT '== END (call with invalid argument) ==' - CLOSE cur_a; - CLOSE @refcur_b; - CLOSE @refcur_c; - SELECT '== AFTER CLOSE =='; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_c'; - EXEC babel_print_sp_cursor_list @report_cur; - DEALLOCATE cur_a; - DEALLOCATE @refcur_b; - DEALLOCATE @refcur_c; - SELECT '== AFTER DEALLOCATE =='; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_a'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'local', 'cur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_b'; - EXEC babel_print_sp_cursor_list @report_cur; - EXEC sp_describe_cursor @report_cur OUT, 'variable', '@refcur_c'; - EXEC babel_print_sp_cursor_list @report_cur; -END; -GO - -EXEC babel_sp_describe_cursor_proc; -GO -~~START~~ -varchar -== AFTER DECLARE == -~~END~~ - -~~START~~ -varchar -(sp_cursor_list out) @refname: cur_a, @curname: cur_a, @scope: 1, @model: 1, @concurrency: 1, @scrollable: 1, @open_status: 0, @cursor_rows: 0, @fetch_status: -9, @column_count: -1, @row_count: 0, @last_operation 0 -~~END~~ - -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: cursor "" does not exist)~~ - - CREATE PROCEDURE babel_same_cursor_name_proc(@opt int) AS BEGIN @@ -3959,13 +3776,13 @@ EXEC babel_sp_cursor_fetch_proc 2, 0, 1; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_close_proc; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_execute_proc; @@ -3978,13 +3795,13 @@ EXEC babel_sp_cursor_fetch_proc 2, 0, 4; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_close_proc; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_unprepare_proc; @@ -4009,13 +3826,13 @@ EXEC babel_sp_cursor_fetch_proc 2, 0, 1; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_close_proc; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_execute_proc; @@ -4028,7 +3845,7 @@ EXEC babel_sp_cursor_fetch_proc 2, 0, 6; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: cursor "180150062" does not exist)~~ +~~ERROR (Message: cursor "180150054" does not exist)~~ EXEC babel_sp_cursor_unprepare_proc; @@ -4269,7 +4086,6 @@ varchar DROP PROCEDURE babel_cursor_proc; -DROP PROCEDURE babel_cursor_no_semi_proc; DROP PROCEDURE babel_cursor_double_precision_proc; DROP PROCEDURE babel_cursor_varchar_proc; DROP PROCEDURE babel_cursor_uniqueidentifier_proc; @@ -4309,13 +4125,6 @@ DROP PROCEDURE babel_cursor_redecl_not_deallocd_proc_2; DROP PROCEDURE babel_cursor_redecl_not_deallocd_proc_3; DROP PROCEDURE babel_cursor_redecl_goto_proc; DROP PROCEDURE babel_cursor_redecl_goto_proc_2; -DROP PROCEDURE babel_fetch_cursor_helper_int_proc; -DROP PROCEDURE babel_fetch_cursor_helper_char_proc; -DROP PROCEDURE babel_sp_cursor_list_proc; -DROP PROCEDURE babel_sp_cursor_list_nested_proc_2; -DROP PROCEDURE babel_sp_cursor_list_nested_proc; -DROP PROCEDURE babel_sp_describe_cursor_proc; -DROP PROCEDURE babel_print_sp_cursor_list; DROP PROCEDURE babel_same_cursor_name_proc; DROP PROCEDURE babel_cursor_rows_proc; DROP PROCEDURE babel_sp_cursor_proc; diff --git a/test/JDBC/expected/babel_datatype.out b/test/JDBC/expected/babel_datatype.out new file mode 100644 index 0000000000..cce059dcac --- /dev/null +++ b/test/JDBC/expected/babel_datatype.out @@ -0,0 +1,3074 @@ +-- 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~~ + + + +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 +~~START~~ +nvarchar +a +~~END~~ + +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_datatype_sqlvariant-vu-cleanup.out b/test/JDBC/expected/babel_datatype_sqlvariant-vu-cleanup.out index 5063c50bd2..8ae54e1a03 100644 --- a/test/JDBC/expected/babel_datatype_sqlvariant-vu-cleanup.out +++ b/test/JDBC/expected/babel_datatype_sqlvariant-vu-cleanup.out @@ -5,6 +5,8 @@ drop table babel_datatype_sqlvariant_vu_prepare_t2; go drop table babel_datatype_sqlvariant_vu_prepare_t3; go +drop table babel_datatype_sqlvariant_vu_prepare_t4; +go drop table babel_datatype_sqlvariant_vu_prepare_t5; go drop table babel_datatype_sqlvariant_vu_prepare_t6; @@ -15,15 +17,15 @@ drop table babel_datatype_sqlvariant_vu_prepare_t8; go drop table babel_datatype_sqlvariant_vu_prepare_t9; go +drop table babel_4036_t1; +go +drop table babel_4036_t2; +go drop sequence babel_datatype_sqlvariant_vu_prepare_t1_sec; go drop sequence babel_datatype_sqlvariant_vu_prepare_t2_sec; go drop sequence babel_datatype_sqlvariant_vu_prepare_t4_sec; go -~~ERROR (Code: 3732)~~ - -~~ERROR (Message: cannot drop sequence babel_datatype_sqlvariant_vu_prepare_t4_sec because other objects depend on it)~~ - drop sequence babel_datatype_sqlvariant_vu_prepare_t5_sec; go diff --git a/test/JDBC/expected/babel_datatype_sqlvariant-vu-prepare.out b/test/JDBC/expected/babel_datatype_sqlvariant-vu-prepare.out index acabff59a0..69ace2f723 100644 --- a/test/JDBC/expected/babel_datatype_sqlvariant-vu-prepare.out +++ b/test/JDBC/expected/babel_datatype_sqlvariant-vu-prepare.out @@ -753,3 +753,170 @@ insert into babel_datatype_sqlvariant_vu_prepare_t9 values (cast('$200' as money go ~~ROW COUNT: 1~~ + +create table babel_4036_t1( a int, b sql_variant, c varchar(50), d sql_variant, e sql_variant); +go + +insert into babel_4036_t1(a,c,e) values (1, 'String 1', cast('Varchar String' as varchar(50))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (2, cast('😊😋😎ðŸ˜ðŸ˜…😆' as nchar(24)), 'String 2', cast('😊😋😎ðŸ˜ðŸ˜…😆' as nchar(26)),cast('😊 😋 😎dsfsd😠😅ds😆' as nchar(24))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (3, cast('12-21-16' as date), 'String 3', cast('12-21-16' as datetime), cast('12-21-16' as datetime2)); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (4, cast('12:10:16.1234567' as time(7)), 'String 4', cast(cast('12:10:16.1234567' as time(7)) as datetime2), cast(cast('12:10:16.1234567' as time(7)) as datetime2(7))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (5, cast('12-01-16 12:32' as smalldatetime), 'String 5', cast('12-01-16 12:32' as datetime2), cast('12-01-16 12:32' as datetime2(5))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (6, cast('2016-10-23 12:45:37.1234567+10:0' as datetime2), 'String 6', cast('2016-10-23 12:45:37.1234567 +10:0' as datetime2(5)), cast('2016-10-23 12:45:37.1234567 +10:0' as datetime2(7))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (8, cast(1234.56789 as numeric(7,2)), 'String 8', cast(1234.56789 as numeric(9,3)), cast(cast(1234.56789 as numeric(9,5)))); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ")")~~ + + +insert into babel_4036_t1 values (8, cast(1234.56789 as decimal(7,2)), 'String 8', cast(1234.56789 as decimal(9,3)), cast(cast(1234.56789 as decimal(9,5)))); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ")")~~ + + +insert into babel_4036_t1 values (10, cast(-0.5678900 as numeric(5,4)), 'String 10', cast(-0.5678900 as numeric(6,5)), cast(-0.5678900 as numeric(7,6))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (10, cast(-0.5678900 as decimal(5,4)), 'String 10', cast(-0.5678900 as decimal(6,5)), cast(-0.5678900 as decimal(7,6))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (11, cast(NULL as decimal), 'String 11', cast(0.0 as decimal), cast(0 as decimal(5,4))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (12, cast(NULL as numeric), 'String 11', cast(0.0 as numeric), cast(0 as numeric(5,4))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (13, CAST('2079-06-06 23:59:29.123456' AS datetime2(0)), 'String 11', CAST('2079-06-06 23:59:29.123456' AS datetime2(1)), CAST('2079-06-06 23:59:29.123456' AS datetime2(2))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (14, CAST('2079-06-06 23:59:29.123456' AS datetime2(3)), 'String 11', CAST('2079-06-06 23:59:29.123456' AS datetime2(4)), CAST('2079-06-06 23:59:29.123456' AS datetime2(5))); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t1 values (15, CAST('2079-06-06 23:59:29.123456' AS datetime2(6)), 'String 11', CAST('2079-06-06 23:59:29.123456' AS datetime2(7)), CAST('2079-06-06 23:59:29.123456' AS datetime2)); +go +~~ROW COUNT: 1~~ + + +-- test generated column for sql_variant column +create table babel_4036_t2 (a int, b as a * a, c sql_variant, d as c, e varchar(50)); +go +-- some corner cases for numeric and decimal datatype +insert into babel_4036_t2 (a, c, e) values(1, CAST('-0.9999999999999996' as numeric(18,17)) ,'String 1'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2 (a, c, e) values(2, CAST(1234567890123.1234567891234567891234567 as numeric(38, 25)) ,'String 2'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(3, cast(0.1234567890123456789012345678901234567 as numeric(38, 37)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(4, cast(99999999999999999999999999999999999999 as numeric(38,0)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(5, cast(0.00000000000000000000000000 as numeric(27,26)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2 (a, c, e) values(6, CAST('-0.9999999999999996' as numeric(18,17)) ,'String 3'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2 (a, c, e) values(7, CAST(1234567890123.1234567891234567891234567 as decimal(38, 25)) ,'String 4'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(8, cast(0.1234567890123456789012345678901234567 as decimal(38, 37)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(9, cast(99999999999999999999999999999999999999 as decimal(38,0)), 'abc'); +go +~~ROW COUNT: 1~~ + + +-- negative test scenarios for numeric and decimal +insert into babel_4036_t2(a, c, e) values(10, cast(-0.00000000000000000000000000 as decimal(27,26)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2 (a, c, e) values(2, CAST(-1234567890123.1234567891234567891234567 as numeric(38, 25)) ,'String 2'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(3, cast(-0.1234567890123456789012345678901234567 as numeric(38, 37)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(4, cast(-99999999999999999999999999999999999999 as numeric(38,0)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2 (a, c, e) values(2, CAST(-1234567890123.1234567891234567891234567 as decimal(38, 25)) ,'String 2'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(3, cast(-0.1234567890123456789012345678901234567 as decimal(38, 37)), 'abc'); +go +~~ROW COUNT: 1~~ + + +insert into babel_4036_t2(a, c, e) values(4, cast(-99999999999999999999999999999999999999 as decimal(38,0)), 'abc'); +go +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/babel_datatype_sqlvariant-vu-verify.out b/test/JDBC/expected/babel_datatype_sqlvariant-vu-verify.out index 813d24a26a..a8d0351e9b 100644 --- a/test/JDBC/expected/babel_datatype_sqlvariant-vu-verify.out +++ b/test/JDBC/expected/babel_datatype_sqlvariant-vu-verify.out @@ -236,6 +236,14 @@ date 2020-10-20 ~~END~~ +-- datetime to float +select cast(cast(cast('2020-10-20 09:00:00' as datetime) as sql_variant) as float); +go +~~START~~ +float +44122.375 +~~END~~ + -- date to datetime2 select cast(cast(cast('2020-10-20' as date) as sql_variant) as datetime2); go @@ -249,7 +257,7 @@ select cast(cast(cast('2020-10-05 09:00:00-9:00' as datetimeoffset) as sql_varia go ~~START~~ datetime2 -2020-10-05 18:00:00.0000000 +2020-10-05 09:00:00.0000000 ~~END~~ -- datetime2 2 datetimeoffset @@ -326,15 +334,6 @@ abc -- CAST examples not supported yet --- datetime to float -select cast(cast(cast('2020-10-20 09:00:00' as datetime) as sql_variant) as float); -go -~~START~~ -float -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: unable to cast from internal type datetime to double precision)~~ - -- time to datetime select cast(cast(cast('09:00:00' as time) as sql_variant) as datetime); go @@ -700,3 +699,46 @@ sql_variant#!#sql_variant 200.0000#!#300 ~~END~~ + +select * from babel_4036_t1 order by a; +go +~~START~~ +int#!#sql_variant#!#varchar#!#sql_variant#!#sql_variant +1#!##!#String 1#!##!#Varchar String +2#!#😊😋😎ðŸ˜ðŸ˜…😆 #!#String 2#!#😊😋😎ðŸ˜ðŸ˜…😆 #!#😊 😋 😎dsfsd😠😅ds😆 +3#!#2016-12-21#!#String 3#!#2016-12-21 00:00:00.0#!#2016-12-21 00:00:00.0 +4#!#12:10:16.1234570#!#String 4#!#1900-01-01 12:10:16.123457#!#1900-01-01 12:10:16.123457 +5#!#2016-12-01 12:32:00.0#!#String 5#!#2016-12-01 12:32:00.0#!#2016-12-01 12:32:00.0 +6#!#2016-10-23 12:45:37.123457#!#String 6#!#2016-10-23 12:45:37.12346#!#2016-10-23 12:45:37.123457 +10#!#-0.5679#!#String 10#!#-0.56789#!#-0.567890 +10#!#-0.5679#!#String 10#!#-0.56789#!#-0.567890 +11#!##!#String 11#!#0#!#0.0000 +12#!##!#String 11#!#0#!#0.0000 +13#!#2079-06-06 23:59:29.0#!#String 11#!#2079-06-06 23:59:29.1#!#2079-06-06 23:59:29.12 +14#!#2079-06-06 23:59:29.123#!#String 11#!#2079-06-06 23:59:29.1235#!#2079-06-06 23:59:29.12346 +15#!#2079-06-06 23:59:29.123456#!#String 11#!#2079-06-06 23:59:29.123456#!#2079-06-06 23:59:29.123456 +~~END~~ + + +select * from babel_4036_t2 order by a; +go +~~START~~ +int#!#int#!#sql_variant#!#sql_variant#!#varchar +1#!#1#!#-0.99999999999999960#!#-0.99999999999999960#!#String 1 +2#!#4#!#-1234567890123.1234567891234567891234567#!#-1234567890123.1234567891234567891234567#!#String 2 +2#!#4#!#1234567890123.1234567891234567891234567#!#1234567890123.1234567891234567891234567#!#String 2 +2#!#4#!#-1234567890123.1234567891234567891234567#!#-1234567890123.1234567891234567891234567#!#String 2 +3#!#9#!#0.1234567890123456789012345678901234567#!#0.1234567890123456789012345678901234567#!#abc +3#!#9#!#-0.1234567890123456789012345678901234567#!#-0.1234567890123456789012345678901234567#!#abc +3#!#9#!#-0.1234567890123456789012345678901234567#!#-0.1234567890123456789012345678901234567#!#abc +4#!#16#!#-99999999999999999999999999999999999999#!#-99999999999999999999999999999999999999#!#abc +4#!#16#!#99999999999999999999999999999999999999#!#99999999999999999999999999999999999999#!#abc +4#!#16#!#-99999999999999999999999999999999999999#!#-99999999999999999999999999999999999999#!#abc +5#!#25#!#0E-26#!#0E-26#!#abc +6#!#36#!#-0.99999999999999960#!#-0.99999999999999960#!#String 3 +7#!#49#!#1234567890123.1234567891234567891234567#!#1234567890123.1234567891234567891234567#!#String 4 +8#!#64#!#0.1234567890123456789012345678901234567#!#0.1234567890123456789012345678901234567#!#abc +9#!#81#!#99999999999999999999999999999999999999#!#99999999999999999999999999999999999999#!#abc +10#!#100#!#0E-26#!#0E-26#!#abc +~~END~~ + diff --git a/test/JDBC/expected/babel_datatype_sqlvariant.out b/test/JDBC/expected/babel_datatype_sqlvariant.out index 7171622f31..17995a5756 100644 --- a/test/JDBC/expected/babel_datatype_sqlvariant.out +++ b/test/JDBC/expected/babel_datatype_sqlvariant.out @@ -443,6 +443,14 @@ date 2020-10-20 ~~END~~ +-- datetime to float +select cast(cast(cast('2020-10-20 09:00:00' as datetime) as sql_variant) as float); +go +~~START~~ +float +44122.375 +~~END~~ + -- date to datetime2 select cast(cast(cast('2020-10-20' as date) as sql_variant) as datetime2); go @@ -456,7 +464,7 @@ select cast(cast(cast('2020-10-05 09:00:00-9:00' as datetimeoffset) as sql_varia go ~~START~~ datetime2 -2020-10-05 18:00:00.0000000 +2020-10-05 09:00:00.0000000 ~~END~~ -- datetime2 2 datetimeoffset @@ -533,15 +541,6 @@ abc -- CAST examples not supported yet --- datetime to float -select cast(cast(cast('2020-10-20 09:00:00' as datetime) as sql_variant) as float); -go -~~START~~ -float -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: unable to cast from internal type datetime to double precision)~~ - -- time to datetime select cast(cast(cast('09:00:00' as time) as sql_variant) as datetime); go diff --git a/test/JDBC/expected/babel_datetime-vu-verify.out b/test/JDBC/expected/babel_datetime-vu-verify.out index 99dde07be1..d6df7886af 100644 --- a/test/JDBC/expected/babel_datetime-vu-verify.out +++ b/test/JDBC/expected/babel_datetime-vu-verify.out @@ -194,21 +194,21 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:12.347 +2079-06-06 23:59:12.347 ~~END~~ -- out of range @@ -376,8 +376,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ - +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) select pg_typeof(c1) FROM (SELECT cast('2016-12-26 23:30:05' as datetime) as C1 UNION SELECT cast('2016-12-26 23:30:05' as smalldatetime) as C1) T diff --git a/test/JDBC/expected/babel_datetime.out b/test/JDBC/expected/babel_datetime.out index d1f3e83c60..804bba9f28 100644 --- a/test/JDBC/expected/babel_datetime.out +++ b/test/JDBC/expected/babel_datetime.out @@ -238,21 +238,21 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:12.347 +2079-06-06 23:59:12.347 ~~END~~ -- out of range @@ -420,7 +420,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/babel_datetime2.out b/test/JDBC/expected/babel_datetime2.out index afb056714c..fdb49852f8 100644 --- a/test/JDBC/expected/babel_datetime2.out +++ b/test/JDBC/expected/babel_datetime2.out @@ -423,35 +423,35 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime2 go ~~START~~ datetime2 -2079-06-06 15:59:29.9980000 +2079-06-06 23:59:29.9980000 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime2); go ~~START~~ datetime2 -2079-06-07 09:29:29.9980000 +2079-06-06 23:59:29.9980000 ~~END~~ select CAST(CAST('2079-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime2); go ~~START~~ datetime2 -2079-06-07 09:29:12.3456780 +2079-06-06 23:59:12.3456780 ~~END~~ select CAST(CAST('0001-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime2); go ~~START~~ datetime2 -0001-06-07 09:29:12.3456780 +0001-06-06 23:59:12.3456780 ~~END~~ select CAST(CAST('0001-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime2(5)); go ~~START~~ datetime2 -0001-06-07 09:29:12.34568 +0001-06-06 23:59:12.34568 ~~END~~ @@ -658,9 +658,9 @@ datetime2 -- out of range select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime2)); go -~~ERROR (Code: 33557097)~~ +~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime2)~~ +~~ERROR (Message: Adding a value to a 'datetime2' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/babel_datetimeoffset.out b/test/JDBC/expected/babel_datetimeoffset.out index 9bb85835a5..24fa9a2eeb 100644 --- a/test/JDBC/expected/babel_datetimeoffset.out +++ b/test/JDBC/expected/babel_datetimeoffset.out @@ -343,14 +343,14 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime); go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99' AS datetime2) AS datetimeoffset); @@ -364,7 +364,7 @@ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS datetime2 go ~~START~~ datetime2 -1900-05-06 21:59:29.9980000 +1900-05-06 13:59:29.9980000 ~~END~~ @@ -431,7 +431,7 @@ select CAST(CAST('1900-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99 +0' AS datetimeoffset) AS time); @@ -466,7 +466,7 @@ select CAST(CAST('2050-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ @@ -475,21 +475,21 @@ select CAST(CAST('2000-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS smalldate go ~~START~~ smalldatetime -2000-06-07 09:29:00.0 +2000-06-06 23:59:00.0 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -2079-06-06 15:59:00.0 +2079-06-06 23:59:00.0 ~~END~~ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -1900-05-06 21:59:00.0 +1900-05-06 13:59:00.0 ~~END~~ select CAST(CAST('2020-03-15 23:59:29.99' AS smalldatetime) AS datetimeoffset); @@ -932,11 +932,82 @@ DECLARE @dto datetimeoffset = CAST('1930-05-06 13:39:29.123456 +0:00' AS datetim exec cmp_datetimeoffset @dto; go +DECLARE @lvDateEastern DATETIME, @lvDateUTC DATETIME +SET @lvDateUTC = '2021-01-01' +SET @lvDateEastern = @lvDateUTC AT TIME ZONE 'UTC' AT TIME ZONE 'US Eastern Standard Time' +SELECT @lvDateUTC, @lvDateEastern +go +~~START~~ +datetime#!#datetime +2021-01-01 00:00:00.0#!#2020-12-31 19:00:00.0 +~~END~~ + + +DECLARE @lvDateEastern DATETIME2, @lvDateUTC DATETIME +SET @lvDateUTC = '2021-01-01' +SET @lvDateEastern = @lvDateUTC AT TIME ZONE 'UTC' AT TIME ZONE 'US Eastern Standard Time' +SELECT @lvDateUTC, @lvDateEastern +go +~~START~~ +datetime#!#datetime2 +2021-01-01 00:00:00.0#!#2020-12-31 19:00:00.0000000 +~~END~~ + + +DECLARE @lvDateEastern SMALLDATETIME, @lvDateUTC DATETIME +SET @lvDateUTC = '2021-01-01' +SET @lvDateEastern = @lvDateUTC AT TIME ZONE 'UTC' AT TIME ZONE 'US Eastern Standard Time' +SELECT @lvDateUTC, @lvDateEastern +go +~~START~~ +datetime#!#smalldatetime +2021-01-01 00:00:00.0#!#2020-12-31 19:00:00.0 +~~END~~ + + +DECLARE @lvDateEastern DATE, @lvDateUTC DATETIME +SET @lvDateUTC = '2021-01-01' +SET @lvDateEastern = @lvDateUTC AT TIME ZONE 'UTC' AT TIME ZONE 'US Eastern Standard Time' +SELECT @lvDateUTC, @lvDateEastern +go +~~START~~ +datetime#!#date +2021-01-01 00:00:00.0#!#2020-12-31 +~~END~~ + + +DECLARE @lvDateEastern TIME, @lvDateUTC DATETIME +SET @lvDateUTC = '2021-01-01' +SET @lvDateEastern = @lvDateUTC AT TIME ZONE 'UTC' AT TIME ZONE 'US Eastern Standard Time' +SELECT @lvDateUTC, @lvDateEastern +go +~~START~~ +datetime#!#time +2021-01-01 00:00:00.0#!#19:00:00.0000000 +~~END~~ + + +Create table implicit_cast ( a datetime) +go +insert into implicit_cast values (cast('1900-05-06 13:59:29.998 -8:00' as datetimeoffset)) +go +~~ROW COUNT: 1~~ + +Select * from implicit_cast +go +~~START~~ +datetime +1900-05-06 13:59:29.997 +~~END~~ + + -- Clean up drop table datetimeoffset_testing; go drop table t1; go +drop table implicit_cast; +go drop procedure cast_datetimeoffset; go drop procedure cmp_datetimeoffset; diff --git a/test/JDBC/expected/babel_ddl.out b/test/JDBC/expected/babel_ddl.out new file mode 100644 index 0000000000..8040840521 --- /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 not null, b int, unique nonclustered (a)); +GO +create table t5 ( a int not null, 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 NULLS FIRST) +t1_idx2t117dbbb74ced1fe936cdf7cd7baeff266#!#CREATE INDEX t1_idx2t117dbbb74ced1fe936cdf7cd7baeff266 ON master_dbo.t1 USING btree (a NULLS FIRST) +t1_idx3t19eceb46c036c3c1bd6895a34ec3c93f1#!#CREATE INDEX t1_idx3t19eceb46c036c3c1bd6895a34ec3c93f1 ON master_dbo.t1 USING btree (a NULLS FIRST) +t1_idx4t1fb4b953a652720bfa47919dff09b172e#!#CREATE INDEX t1_idx4t1fb4b953a652720bfa47919dff09b172e ON master_dbo.t1 USING btree (a NULLS FIRST) +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 not null, unique clustered (a) on [PRIMARY]); +GO +create table t20(a int not null, 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_delete.out b/test/JDBC/expected/babel_delete.out index 9f40f89b41..16efd9de59 100644 --- a/test/JDBC/expected/babel_delete.out +++ b/test/JDBC/expected/babel_delete.out @@ -36,6 +36,48 @@ go ~~ROW COUNT: 1~~ +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output deleted.a +from babel_2020_delete_t1 x where x.a = 2; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +2 +~~END~~ + + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output deleted.a +from babel_2020_delete_t1 where a = 2; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +2 +~~END~~ + + +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output deleted.a +from babel_2020_delete_t1 where babel_2020_delete_t1.a = 2; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +2 +~~END~~ + + -- multiple tables in FROM clause exec babel_2020_delete_ct; delete babel_2020_delete_t1 from babel_2020_delete_t1 x, babel_2020_delete_t2 y; @@ -77,6 +119,20 @@ go ~~ROW COUNT: 1~~ +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output y.* +from babel_2020_delete_t1 x, babel_2020_delete_t2 y where x.a = y.a; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +2 +~~END~~ + + -- JOIN clause exec babel_2020_delete_ct; delete babel_2020_delete_t1 from babel_2020_delete_t1 x join babel_2020_delete_t2 y on 1 = 1; @@ -118,6 +174,21 @@ go ~~ROW COUNT: 1~~ +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output deleted.a, y.a +from babel_2020_delete_t1 x join babel_2020_delete_t2 y on x.a = y.a; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int#!#int +2#!#2 +~~END~~ + + + -- subqueries exec babel_2020_delete_ct; delete babel_2020_delete_t1 from (select * from babel_2020_delete_t1) x; @@ -201,6 +272,23 @@ go ~~ROW COUNT: 3~~ +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output deleted.*, babel_2020_delete_t2.* +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~~ + +~~START~~ +int#!#int +1#!# +2#!#2 +#!# +~~END~~ + + -- will be tracked in BABEL-3910 drop procedure if exists babel_3910_init_tables go @@ -341,6 +429,26 @@ int ~~END~~ +exec babel_3910_init_tables +delete t1_3910 output deleted.* +from (t2_3910 left join t1_3910 on t1_3910.a = t2_3910.a) + join t3_3910 on t2_3910.a = t3_3910.a; +go +~~ROW COUNT: 5~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 5~~ + +~~START~~ +int +3 +4 +~~END~~ + + exec babel_3910_init_tables delete t1_3910 from @@ -458,6 +566,27 @@ go ~~ROW COUNT: 3~~ +exec babel_3910_init_tables; +delete t1 output t2.* +from t2_3910 t2 left outer join t1_3910 t1 on t2.a = t1.a +where 0 < t1.a OR t1.a < 10; +go +~~ROW COUNT: 5~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 5~~ + +~~START~~ +int +2 +3 +4 +~~END~~ + + select a from t1_3910; go ~~START~~ @@ -546,6 +675,20 @@ go ~~ROW COUNT: 1~~ +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output babel_2020_delete_t2.* +from babel_2020_delete_t2 left outer join babel_2020_delete_t1 x on x.a is null; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +2 +~~END~~ + + -- updatable views drop view if exists babel_2020_delete_v1; go @@ -599,6 +742,21 @@ go ~~ROW COUNT: 1~~ +exec babel_2020_delete_ct; +delete babel_2020_delete_t1 output deleted.* +from babel_2020_delete_t1 x where exists +(select a from babel_2020_delete_t1 y where y.a + 1 = x.a); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +2 +~~END~~ + + drop procedure if exists babel_2020_delete_ct; drop table if exists babel_2020_delete_t1; drop table if exists babel_2020_delete_t2; @@ -659,6 +817,23 @@ int#!#varchar ~~END~~ +BEGIN TRAN +DELETE t1 OUTPUT deleted.* +FROM babel_delete_tbl1 t1 +SELECT * FROM babel_delete_tbl1 +ROLLBACK +GO +~~START~~ +int#!#varchar +1#!#left +2#!#inner +~~END~~ + +~~START~~ +int#!#varchar +~~END~~ + + -- alias + subquery BEGIN TRAN DELETE t1 @@ -675,6 +850,25 @@ int#!#varchar ~~END~~ +BEGIN TRAN +DELETE t1 OUTPUT t2.b +FROM babel_delete_tbl1 t1 +INNER JOIN (SELECT * FROM babel_delete_tbl1) t2 +ON t1.b = t2.b +SELECT * FROM babel_delete_tbl1 +ROLLBACK +GO +~~START~~ +varchar +inner +left +~~END~~ + +~~START~~ +int#!#varchar +~~END~~ + + -- alias + join BEGIN TRAN DELETE t1 @@ -741,6 +935,24 @@ int#!#int ~~END~~ +BEGIN TRAN +DELETE t1 output deleted.* +FROM babel_delete_tbl1 t2, babel_delete_tbl3 t1 +WHERE c > 1 +SELECT * FROM babel_delete_tbl3 +ROLLBACK +go +~~START~~ +int#!#int +1#!#10 +3#!#10 +~~END~~ + +~~START~~ +int#!#int +~~END~~ + + -- alias + outer join BEGIN TRAN DELETE t1 @@ -816,6 +1028,23 @@ int ~~END~~ +BEGIN TRAN +DELETE t1 output deleted.* +FROM babel_delete_schema.babel_delete_tbl1 t1 +SELECT * fROM babel_delete_schema.babel_delete_tbl1 +ROLLBACK +GO +~~START~~ +int +1 +2 +~~END~~ + +~~START~~ +int +~~END~~ + + -- target with schema BEGIN TRAN DELETE babel_delete_schema.babel_delete_tbl1 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..427c0a6917 --- /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 +1900-05-04 00:00:00.0 +~~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.123 +~~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 +#!##!#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 +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; +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 +#!##!#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 +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; +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_function_string-before-15-5-or-14-10-vu-prepare.out b/test/JDBC/expected/babel_function_string-before-15-5-or-14-10-vu-prepare.out new file mode 100644 index 0000000000..e16f0ffe48 --- /dev/null +++ b/test/JDBC/expected/babel_function_string-before-15-5-or-14-10-vu-prepare.out @@ -0,0 +1,42 @@ +-- additional tests for DATALENGTH (more types, nullvalues) +CREATE table babel_function_string_vu_prepare_1 (a binary(10), b image, c varbinary(10), d char(10), + e varchar(10), f text, g nchar(10), h nvarchar(10), i ntext) +GO + +INSERT into babel_function_string_vu_prepare_1 values (cast('abc' as binary(10)), cast('abc' as image), cast('abc' as varbinary(10)),'abc','abc','abc','abc','abc','abc') +GO +~~ROW COUNT: 1~~ + + +INSERT into babel_function_string_vu_prepare_1 values (null, null, null, null, null, null,null, null, null) +GO +~~ROW COUNT: 1~~ + + +CREATE table babel_function_string_vu_prepare_2 (a integer, b bigint, c bit, d smallint, e tinyint, f decimal, g numeric, h float, i real) +GO + +INSERT into babel_function_string_vu_prepare_2 values (1, 1, 1, 1, 1, 1, 1, 1, 1) +GO +~~ROW COUNT: 1~~ + + +INSERT into babel_function_string_vu_prepare_2 values (null, null, null, null, null, null,null, null, null) +GO +~~ROW COUNT: 1~~ + + +CREATE table babel_function_string_vu_prepare_3 (a smallmoney, b money, c date, d datetime, e datetime2, f smalldatetime, g time, h uniqueidentifier) +GO + +INSERT into babel_function_string_vu_prepare_3 values (cast(1 as smallmoney), cast(1 as money), cast('2020-02-20' as date), cast('2020-02-20 20:20:20.888' as datetime), + cast('2020-02-20 20:20:20.88888' as datetime2), cast('2020-02-20 20:20:20' as smalldatetime), cast('20:20:20.888' as time), + cast('6F9619FF-8B86-D011-B42D-00C04FC964FF' as uniqueidentifier)) +GO +~~ROW COUNT: 1~~ + + +INSERT into babel_function_string_vu_prepare_3 values (null, null, null, null, null, null,null, null) +GO +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/babel_function_string-before-15-5-or-14-10-vu-verify.out b/test/JDBC/expected/babel_function_string-before-15-5-or-14-10-vu-verify.out new file mode 100644 index 0000000000..4e0207f9ff --- /dev/null +++ b/test/JDBC/expected/babel_function_string-before-15-5-or-14-10-vu-verify.out @@ -0,0 +1,789 @@ +-- test REPLICATE function +SELECT REPLICATE(' abc ', 3) +GO +~~START~~ +varchar + abc abc abc +~~END~~ + + +SELECT REPLICATE(N'abc', 3) +GO +~~START~~ +varchar +abcabcabc +~~END~~ + + +SELECT REPLICATE(' abc ', 0) +GO +~~START~~ +varchar + +~~END~~ + + +-- test null condition +SELECT REPLICATE('abc', -3) +GO +~~START~~ +varchar + +~~END~~ + + +SELECT REPLICATE(null, 1) +GO +~~START~~ +varchar + +~~END~~ + + +-- test LEN and DATALENGTH functions +SELECT LEN(N'123') +GO +~~START~~ +int +3 +~~END~~ + + +SELECT LEN(N'123 ') +GO +~~START~~ +int +3 +~~END~~ + + +SELECT LEN(N' 123 ') +GO +~~START~~ +int +6 +~~END~~ + + +SELECT LEN(CAST('123' as char(25))) +GO +~~START~~ +int +3 +~~END~~ + + +SELECT LEN('abc') +GO +~~START~~ +int +3 +~~END~~ + + +SELECT LEN('abc' + 'def') +GO +~~START~~ +int +6 +~~END~~ + + +SELECT LEN('tamaño') +GO +~~START~~ +int +6 +~~END~~ + + +SELECT DATALENGTH(N'123') +GO +~~START~~ +int +3 +~~END~~ + + +SELECT DATALENGTH(N'123 ') +GO +~~START~~ +int +6 +~~END~~ + + +SELECT DATALENGTH(N' 123 ') +GO +~~START~~ +int +9 +~~END~~ + + +SELECT DATALENGTH(CAST('123' as char(25))) +GO +~~START~~ +int +25 +~~END~~ + + +SELECT DATALENGTH('ab' + 'def') +GO +~~START~~ +int +5 +~~END~~ + + +SELECT DATALENGTH('哈哈12345') +GO +~~START~~ +int +11 +~~END~~ + + +-- additional tests for DATALENGTH (more types, nullvalues) +SELECT datalength(a), datalength(b),datalength(c),datalength(d),datalength(e), + datalength(f),datalength(g),datalength(h),datalength(i) FROM babel_function_string_vu_prepare_1 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +3#!#3#!#3#!#10#!#3#!#3#!#10#!#3#!#3 +#!##!##!##!##!##!##!##!# +~~END~~ + + +SELECT datalength(a), datalength(b),datalength(c),datalength(d),datalength(e), datalength(f),datalength(g),datalength(h),datalength(i) FROM babel_function_string_vu_prepare_2 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +4#!#8#!#1#!#2#!#2#!#4#!#4#!#8#!#4 +#!##!##!##!##!##!##!##!# +~~END~~ + + +SELECT datalength(a), datalength(b),datalength(c),datalength(d),datalength(e), datalength(f),datalength(g),datalength(h) FROM babel_function_string_vu_prepare_3 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int +8#!#8#!#4#!#8#!#8#!#8#!#8#!#16 +#!##!##!##!##!##!##!# +~~END~~ + + +-- test quotename function +SELECT quotename('hardrada', ']') +GO +~~START~~ +nvarchar +[hardrada] +~~END~~ + + +SELECT quotename('gershwin', '<') +GO +~~START~~ +nvarchar +>gershwin< +~~END~~ + + +SELECT quotename('faulkner', '>') +GO +~~START~~ +nvarchar +>faulkner< +~~END~~ + + +SELECT quotename('edgerton', '(') +GO +~~START~~ +nvarchar +(edgerton) +~~END~~ + + +SELECT quotename('denali', ')') +GO +~~START~~ +nvarchar +(denali) +~~END~~ + + +SELECT quotename('charisma', '{') +GO +~~START~~ +nvarchar +{charisma} +~~END~~ + + +SELECT quotename('banana', '}') +GO +~~START~~ +nvarchar +{banana} +~~END~~ + + +SELECT quotename('aardvark', '`') +GO +~~START~~ +nvarchar +`aardvark` +~~END~~ + + +SELECT quotename('128 characters exactly----------------------------------------------------------------------------------------------------------') +GO +~~START~~ +nvarchar +[128 characters exactly----------------------------------------------------------------------------------------------------------] +~~END~~ + + +SELECT +quotename(']]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]') +GO +~~START~~ +nvarchar +[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] +~~END~~ + + +SELECT +quotename('""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""') +GO +~~START~~ +nvarchar +[""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""] +~~END~~ + + +SELECT quotename('''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''') +GO +~~START~~ +nvarchar +[''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''] +~~END~~ + + +SELECT quotename('') +GO +~~START~~ +nvarchar +[] +~~END~~ + + +-- regtype error expected pending BABEL-883 +SELECT pg_typeof(quotename('a')) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data type regtype is not supported yet)~~ + + +SELECT quotename(CAST('abc' as varchar)) +GO +~~START~~ +nvarchar +[abc] +~~END~~ + + +SELECT quotename(CAST('abc' as sys.nvarchar)) +GO +~~START~~ +nvarchar +[abc] +~~END~~ + + +SELECT quotename(CAST('abc' as text)) +GO +~~START~~ +nvarchar +[abc] +~~END~~ + + +SELECT quotename('invalid char', 'F') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT quotename('too long char', 'aa') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT quotename('129 characters exactly-----------------------------------------------------------------------------------------------------------') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT quotename('default should be bracket') +GO +~~START~~ +nvarchar +[default should be bracket] +~~END~~ + + +SELECT quotename('abc [] def') +GO +~~START~~ +nvarchar +[abc []] def] +~~END~~ + + +SELECT quotename(NULL) +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT quotename(NULL, NULL) +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT quotename('hey', NULL) +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT quotename(NULL, '[') +GO +~~START~~ +nvarchar + +~~END~~ + + + +-- test unicode function +SELECT unicode(null) +GO +~~START~~ +int + +~~END~~ + + +SELECT unicode('Ã…kergatan 24') +GO +~~START~~ +int +197 +~~END~~ + + +SELECT nchar(unicode('Ã…kergatan 24')) +GO +~~START~~ +nvarchar +Ã… +~~END~~ + + +SELECT unicode(cast('Ä€mazon' AS nvarchar)) +GO +~~START~~ +int +256 +~~END~~ + + +SELECT unicode(CAST('Ä€mazon' as nvarchar)) +GO +~~START~~ +int +256 +~~END~~ + + +SELECT unicode(cast('Æ‚' as nchar)) +GO +~~START~~ +int +386 +~~END~~ + + +SELECT unicode(CAST('Æ‚' as nchar)) +GO +~~START~~ +int +386 +~~END~~ + + +SELECT STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ') +GO +~~START~~ +varchar +Lorem +ipsum +dolor +sit +amet. +~~END~~ + + +SELECT STRING_SPLIT('clothing,road,,touring,bike', ',') +GO +~~START~~ +varchar +clothing +road + +touring +bike +~~END~~ + + +SELECT STRING_SPLIT('||||||||', '|') +GO +~~START~~ +varchar + + + + + + + + + +~~END~~ + + +SELECT STRING_SPLIT(NULL, ' ') +GO +~~START~~ +varchar +~~END~~ + + +-- test invalid separator +SELECT STRING_SPLIT('asdf', '') +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid separator: )~~ + + +SELECT STRING_SPLIT('asdf', NULL) +GO +~~START~~ +varchar +~~END~~ + + +SELECT STRING_SPLIT(NULL, NULL) +GO +~~START~~ +varchar +~~END~~ + + +SELECT STRING_SPLIT(CAST('nvarchar nvarchar nvarchar' as nvarchar), CAST(' ' as nvarchar)) +GO +~~START~~ +varchar +nvarchar +nvarchar +nvarchar +~~END~~ + + +SELECT STRING_SPLIT(CAST('varchar varchar varchar' as varchar), CAST(' ' as varchar)) +GO +~~START~~ +varchar +varchar +varchar +varchar +~~END~~ + + +SELECT STRING_SPLIT('char char char', ' ') +GO +~~START~~ +varchar +char +char +char +~~END~~ + + +SELECT STRING_SPLIT('a,b,c,d', ',') +GO +~~START~~ +varchar +a +b +c +d +~~END~~ + + +SELECT STRING_SPLIT('mississippi island lives in igloo', 'i') +GO +~~START~~ +varchar +m +ss +ss +pp + +sland l +ves +n +gloo +~~END~~ + + +SELECT STRING_SPLIT(CAST('asdf' as nchar(4)), ' ') +GO +~~START~~ +varchar +asdf +~~END~~ + + +SELECT STRING_SPLIT(CAST('asdf' as char(4)), ' ') +GO +~~START~~ +varchar +asdf +~~END~~ + + +-- test invalid separator +SELECT STRING_SPLIT('Lorem ipsum', 'too many chars') +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid separator: too many chars)~~ + + +SELECT value FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ') +GO +~~START~~ +varchar +Lorem +ipsum +dolor +sit +amet. +~~END~~ + + +SELECT mycol FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "mycol" does not exist)~~ + + + +-- STRING_ESCAPE tests +SELECT STRING_ESCAPE('foo', 'notjson') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT STRING_ESCAPE('foo', '') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT STRING_ESCAPE('foo', NULL) +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT STRING_ESCAPE(NULL, '') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT STRING_ESCAPE(NULL, NULL) +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT STRING_ESCAPE(NULL, 'json') +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT STRING_ESCAPE(' ', 'json') +GO +~~START~~ +nvarchar +\t +~~END~~ + + +SELECT STRING_ESCAPE('"', 'json') +GO +~~START~~ +nvarchar +\" +~~END~~ + + +SELECT STRING_ESCAPE('\', 'json') +GO +~~START~~ +nvarchar +\\ +~~END~~ + + +SELECT STRING_ESCAPE('/', 'json') +GO +~~START~~ +nvarchar +\/ +~~END~~ + + +SELECT STRING_ESCAPE(chr(1), 'json') +GO +~~START~~ +nvarchar +\u0001 +~~END~~ + + +SELECT STRING_ESCAPE(chr(2), 'json') +GO +~~START~~ +nvarchar +\u0002 +~~END~~ + + +SELECT STRING_ESCAPE(chr(8), 'json') +GO +~~START~~ +nvarchar +\b +~~END~~ + + +SELECT STRING_ESCAPE(chr(9), 'json') +GO +~~START~~ +nvarchar +\t +~~END~~ + + +SELECT STRING_ESCAPE(' +', 'json') +GO +~~START~~ +nvarchar +\n +~~END~~ + + +SELECT STRING_ESCAPE(chr(10), 'json') +GO +~~START~~ +nvarchar +\n +~~END~~ + + +SELECT STRING_ESCAPE(chr(11), 'json') +GO +~~START~~ +nvarchar +\u000b +~~END~~ + + +SELECT STRING_ESCAPE(chr(12), 'json') +GO +~~START~~ +nvarchar +\f +~~END~~ + + +SELECT STRING_ESCAPE(chr(13), 'json') +GO +~~START~~ +nvarchar +\r +~~END~~ + + +SELECT STRING_ESCAPE(chr(31), 'json') +GO +~~START~~ +nvarchar +\u001f +~~END~~ + + +SELECT STRING_ESCAPE('lorem ipsum dolor amet +consectetur adipiscing elit', 'json') +GO +~~START~~ +nvarchar +lorem ipsum dolor amet\t\nconsectetur adipiscing elit +~~END~~ + diff --git a/test/JDBC/expected/babel_function_string-vu-verify.out b/test/JDBC/expected/babel_function_string-vu-verify.out index 4e0207f9ff..b63ef75e2d 100644 --- a/test/JDBC/expected/babel_function_string-vu-verify.out +++ b/test/JDBC/expected/babel_function_string-vu-verify.out @@ -151,7 +151,7 @@ SELECT datalength(a), datalength(b),datalength(c),datalength(d),datalength(e), GO ~~START~~ int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int -3#!#3#!#3#!#10#!#3#!#3#!#10#!#3#!#3 +10#!#3#!#3#!#10#!#3#!#3#!#10#!#3#!#3 #!##!##!##!##!##!##!##!# ~~END~~ diff --git a/test/JDBC/expected/babel_function_string.out b/test/JDBC/expected/babel_function_string.out index 13bd5d712b..82cd9cddf3 100644 --- a/test/JDBC/expected/babel_function_string.out +++ b/test/JDBC/expected/babel_function_string.out @@ -165,7 +165,7 @@ SELECT datalength(a), datalength(b),datalength(c),datalength(d),datalength(e), GO ~~START~~ int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int -3#!#3#!#3#!#10#!#3#!#3#!#10#!#3#!#3 +10#!#3#!#3#!#10#!#3#!#3#!#10#!#3#!#3 #!##!##!##!##!##!##!##!# ~~END~~ diff --git a/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-cleanup.out b/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-cleanup.out new file mode 100644 index 0000000000..bd7ac95feb --- /dev/null +++ b/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-cleanup.out @@ -0,0 +1,27 @@ +DROP VIEW babel_index_nulls_order_before_15_5_a_v1 +go +DROP VIEW babel_index_nulls_order_before_15_5_a_v2 +go +DROP VIEW babel_index_nulls_order_before_15_5_a_v3 +go +DROP VIEW babel_index_nulls_order_before_15_5_b_v1 +go +DROP VIEW babel_index_nulls_order_before_15_5_b_v2 +go +DROP VIEW babel_index_nulls_order_before_15_5_b_v3 +go +DROP VIEW babel_index_nulls_order_before_15_5_ab_v1 +go +DROP VIEW babel_index_nulls_order_before_15_5_ab_v2 +go +DROP VIEW babel_index_nulls_order_before_15_5_ab_v3 +go +DROP VIEW babel_index_nulls_order_before_15_5_ab_v4 +go +DROP VIEW babel_index_nulls_order_before_15_5_ab_v5 +go +DROP VIEW babel_index_nulls_order_before_15_5_ab_v6 +go + +DROP TABLE babel_index_nulls_order_before_15_5_tbl +go diff --git a/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-prepare.out b/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-prepare.out new file mode 100644 index 0000000000..6e89b8082b --- /dev/null +++ b/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-prepare.out @@ -0,0 +1,78 @@ +CREATE TABLE babel_index_nulls_order_before_15_5_tbl (a INT, b VARCHAR(10)) +go + +INSERT INTO babel_index_nulls_order_before_15_5_tbl VALUES +(1, 'abc'), (2, 'def'), (3, 'ghi'), (4, 'jkl'), +(5, 'mno'), (6, 'pqr'), (7, 'stu'), (8, 'xyz'), +(1, 'abc'), (2, 'def'), (3, 'ghi'), (4, 'jkl'), +(5, 'mno'), (6, 'pqr'), (7, 'stu'), (8, 'xyz'), +(NULL, NULL) +go +~~ROW COUNT: 17~~ + + +CREATE INDEX babel_index_nulls_order_before_15_5_asc_idx_a ON babel_index_nulls_order_before_15_5_tbl (a ASC) +go +CREATE INDEX babel_index_nulls_order_before_15_5_desc_idx_b ON babel_index_nulls_order_before_15_5_tbl (b DESC) +go +CREATE INDEX babel_index_nulls_order_before_15_5_default_idx_ab ON babel_index_nulls_order_before_15_5_tbl (a, b) +go + +SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'babel_index_nulls_order_before_15_5_tbl' +ORDER BY indexname +go +~~START~~ +varchar#!#text +babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f#!#CREATE INDEX babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f ON master_dbo.babel_index_nulls_order_before_15_5_tbl USING btree (a) +babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5#!#CREATE INDEX babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 ON master_dbo.babel_index_nulls_order_before_15_5_tbl USING btree (b DESC) +babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27#!#CREATE INDEX babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 ON master_dbo.babel_index_nulls_order_before_15_5_tbl USING btree (a, b) +~~END~~ + + +CREATE VIEW babel_index_nulls_order_before_15_5_a_v1 AS +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a <= 5 OR a IS NULL ORDER BY a DESC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_a_v2 AS +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a > 5 OR a IS NULL ORDER BY a ASC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_a_v3 AS +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a > 5 OR a IS NULL ORDER BY a +go + +CREATE VIEW babel_index_nulls_order_before_15_5_b_v1 AS +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b <= 'sss' OR b IS NULL ORDER BY b DESC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_b_v2 AS +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b > 'sss' OR b IS NULL ORDER BY b ASC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_b_v3 AS +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b > 'sss' OR b IS NULL ORDER BY b +go + +CREATE VIEW babel_index_nulls_order_before_15_5_ab_v1 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') OR b IS NULL ORDER BY b DESC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_ab_v2 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') OR b IS NULL ORDER BY b ASC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_ab_v3 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') OR b IS NULL ORDER BY b +go + +CREATE VIEW babel_index_nulls_order_before_15_5_ab_v4 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a > 5 AND b = 'xyz') OR a IS NULL ORDER BY a DESC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_ab_v5 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a > 5 AND b = 'xyz') OR a IS NULL ORDER BY a ASC +go + +CREATE VIEW babel_index_nulls_order_before_15_5_ab_v6 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a > 5 AND b = 'xyz') OR a IS NULL ORDER BY a +go diff --git a/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-verify.out b/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-verify.out new file mode 100644 index 0000000000..09f5304d2c --- /dev/null +++ b/test/JDBC/expected/babel_index_nulls_order-before-15-5-vu-verify.out @@ -0,0 +1,460 @@ +-- Nulls check +SELECT * FROM babel_index_nulls_order_before_15_5_a_v1 +go +~~START~~ +int +5 +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_a_v2 +go +~~START~~ +int + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_a_v3 +go +~~START~~ +int + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_b_v1 +go +~~START~~ +varchar +pqr +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_b_v2 +go +~~START~~ +varchar + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_b_v3 +go +~~START~~ +varchar + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v1 +go +~~START~~ +int#!#varchar +3#!#ghi +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v2 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v3 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v4 +go +~~START~~ +int#!#varchar +8#!#xyz +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v5 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v6 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + + +-- Using indexes created on old versions, queries cannot be optimized +-- Should see sort step for all following queries +SELECT set_config('babelfishpg_tsql.enable_pg_hint', 'on', false) +go +~~START~~ +text +on +~~END~~ + +SELECT set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~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~~ + +SET babelfish_showplan_all ON +go + +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_asc_idx_a)) WHERE a <= 5 ORDER BY a DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f) */ TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a <= 5 ORDER BY a DESC +Limit + -> Sort + Sort Key: a DESC NULLS LAST + -> Index Scan using babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f on babel_index_nulls_order_before_15_5_tbl + Index Cond: (a <= 5) +~~END~~ + +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_asc_idx_a)) WHERE a > 5 ORDER BY a ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f) */ TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a > 5 ORDER BY a ASC +Limit + -> Sort + Sort Key: a NULLS FIRST + -> Index Scan using babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f on babel_index_nulls_order_before_15_5_tbl + Index Cond: (a > 5) +~~END~~ + +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_asc_idx_a)) WHERE a > 5 ORDER BY a +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f) */ TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a > 5 ORDER BY a +Limit + -> Sort + Sort Key: a NULLS FIRST + -> Index Scan using babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f on babel_index_nulls_order_before_15_5_tbl + Index Cond: (a > 5) +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (bel_index_nulls_order_before_15_5_desc_idx_b)) WHERE b <= 'sss' ORDER BY b DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl bel_index_nulls_order_before_15ddb71b88216e14ad4d8372c9021114b4) */ TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b <= 'sss' ORDER BY b DESC +Limit + -> Sort + Sort Key: b DESC NULLS LAST + -> Index Only Scan using babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 on babel_index_nulls_order_before_15_5_tbl + Index Cond: (b <= 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (bel_index_nulls_order_before_15_5_desc_idx_b)) WHERE b > 'sss' ORDER BY b ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl bel_index_nulls_order_before_15ddb71b88216e14ad4d8372c9021114b4) */ TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b > 'sss' ORDER BY b ASC +Limit + -> Sort + Sort Key: b NULLS FIRST + -> Index Only Scan using babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 on babel_index_nulls_order_before_15_5_tbl + Index Cond: (b > 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (bel_index_nulls_order_before_15_5_desc_idx_b)) WHERE b > 'sss' ORDER BY b +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl bel_index_nulls_order_before_15ddb71b88216e14ad4d8372c9021114b4) */ TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b > 'sss' ORDER BY b +Limit + -> Sort + Sort Key: b NULLS FIRST + -> Index Only Scan using babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 on babel_index_nulls_order_before_15_5_tbl + Index Cond: (b > 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27) */ TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b DESC +Limit + -> Sort + Sort Key: b DESC NULLS LAST + -> Index Scan using babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 on babel_index_nulls_order_before_15_5_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27) */ TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b ASC +Limit + -> Sort + Sort Key: b NULLS FIRST + -> Index Scan using babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 on babel_index_nulls_order_before_15_5_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27) */ TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b +Limit + -> Sort + Sort Key: b NULLS FIRST + -> Index Scan using babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 on babel_index_nulls_order_before_15_5_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + + +-- Reset +SET babelfish_showplan_all OFF +go + +-- Recreate indexes +DROP INDEX babel_index_nulls_order_before_15_5_asc_idx_a ON babel_index_nulls_order_before_15_5_tbl +go +DROP INDEX babel_index_nulls_order_before_15_5_desc_idx_b ON babel_index_nulls_order_before_15_5_tbl +go +DROP INDEX babel_index_nulls_order_before_15_5_default_idx_ab ON babel_index_nulls_order_before_15_5_tbl +go + +CREATE INDEX babel_index_nulls_order_before_15_5_asc_idx_a ON babel_index_nulls_order_before_15_5_tbl (a ASC) +go +CREATE INDEX babel_index_nulls_order_before_15_5_desc_idx_b ON babel_index_nulls_order_before_15_5_tbl (b DESC) +go +CREATE INDEX babel_index_nulls_order_before_15_5_default_idx_ab ON babel_index_nulls_order_before_15_5_tbl (a, b) +go + +-- Nulls check +SELECT * FROM babel_index_nulls_order_before_15_5_a_v1 +go +~~START~~ +int +5 +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_a_v2 +go +~~START~~ +int + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_a_v3 +go +~~START~~ +int + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_b_v1 +go +~~START~~ +varchar +pqr +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_b_v2 +go +~~START~~ +varchar + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_b_v3 +go +~~START~~ +varchar + +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v1 +go +~~START~~ +int#!#varchar +3#!#ghi +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v2 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v3 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v4 +go +~~START~~ +int#!#varchar +8#!#xyz +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v5 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_before_15_5_ab_v6 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + + +-- Check query plans, all aggregations should be optimized +-- into LIMIT + index scan +SET babelfish_showplan_all ON +go + +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_asc_idx_a)) WHERE a <= 5 ORDER BY a DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f) */ TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a <= 5 ORDER BY a DESC +Limit + -> Index Scan Backward using babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f on babel_index_nulls_order_before_15_5_tbl + Index Cond: (a <= 5) +~~END~~ + +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_asc_idx_a)) WHERE a > 5 ORDER BY a ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f) */ TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a > 5 ORDER BY a ASC +Limit + -> Index Scan using babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f on babel_index_nulls_order_before_15_5_tbl + Index Cond: (a > 5) +~~END~~ + +SELECT TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_asc_idx_a)) WHERE a > 5 ORDER BY a +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f) */ TOP 1 a FROM babel_index_nulls_order_before_15_5_tbl WHERE a > 5 ORDER BY a +Limit + -> Index Scan using babel_index_nulls_order_before_30830e881ab976e13169ff1709b1917f on babel_index_nulls_order_before_15_5_tbl + Index Cond: (a > 5) +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (bel_index_nulls_order_before_15_5_desc_idx_b)) WHERE b <= 'sss' ORDER BY b DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl bel_index_nulls_order_before_15ddb71b88216e14ad4d8372c9021114b4) */ TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b <= 'sss' ORDER BY b DESC +Limit + -> Index Only Scan using babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 on babel_index_nulls_order_before_15_5_tbl + Index Cond: (b <= 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (bel_index_nulls_order_before_15_5_desc_idx_b)) WHERE b > 'sss' ORDER BY b ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl bel_index_nulls_order_before_15ddb71b88216e14ad4d8372c9021114b4) */ TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b > 'sss' ORDER BY b ASC +Limit + -> Index Only Scan Backward using babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 on babel_index_nulls_order_before_15_5_tbl + Index Cond: (b > 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (bel_index_nulls_order_before_15_5_desc_idx_b)) WHERE b > 'sss' ORDER BY b +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl bel_index_nulls_order_before_15ddb71b88216e14ad4d8372c9021114b4) */ TOP 1 b FROM babel_index_nulls_order_before_15_5_tbl WHERE b > 'sss' ORDER BY b +Limit + -> Index Only Scan Backward using babel_index_nulls_order_before_713975587e1cf6ee0c2fe82e930b89b5 on babel_index_nulls_order_before_15_5_tbl + Index Cond: (b > 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27) */ TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b DESC +Limit + -> Index Scan Backward using babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 on babel_index_nulls_order_before_15_5_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27) */ TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b ASC +Limit + -> Index Scan using babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 on babel_index_nulls_order_before_15_5_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WITH (INDEX (babel_index_nulls_order_before_15_5_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_before_15_5_tbl babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27) */ TOP 1 a, b FROM babel_index_nulls_order_before_15_5_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b +Limit + -> Index Scan using babel_index_nulls_order_before_a61e61121b6bd5392507d3ac38f74f27 on babel_index_nulls_order_before_15_5_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + + +-- Reset +SET babelfish_showplan_all OFF +go +SELECT set_config('babelfishpg_tsql.enable_pg_hint', 'off', false) +go +~~START~~ +text +off +~~END~~ + +SELECT set_config('babelfishpg_tsql.explain_costs', 'on', false) +go +~~START~~ +text +on +~~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~~ + diff --git a/test/JDBC/expected/babel_index_nulls_order-vu-cleanup.out b/test/JDBC/expected/babel_index_nulls_order-vu-cleanup.out new file mode 100644 index 0000000000..ab23dc689f --- /dev/null +++ b/test/JDBC/expected/babel_index_nulls_order-vu-cleanup.out @@ -0,0 +1,27 @@ +DROP VIEW babel_index_nulls_order_a_v1 +go +DROP VIEW babel_index_nulls_order_a_v2 +go +DROP VIEW babel_index_nulls_order_a_v3 +go +DROP VIEW babel_index_nulls_order_b_v1 +go +DROP VIEW babel_index_nulls_order_b_v2 +go +DROP VIEW babel_index_nulls_order_b_v3 +go +DROP VIEW babel_index_nulls_order_ab_v1 +go +DROP VIEW babel_index_nulls_order_ab_v2 +go +DROP VIEW babel_index_nulls_order_ab_v3 +go +DROP VIEW babel_index_nulls_order_ab_v4 +go +DROP VIEW babel_index_nulls_order_ab_v5 +go +DROP VIEW babel_index_nulls_order_ab_v6 +go + +DROP TABLE babel_index_nulls_order_tbl +go diff --git a/test/JDBC/expected/babel_index_nulls_order-vu-prepare.out b/test/JDBC/expected/babel_index_nulls_order-vu-prepare.out new file mode 100644 index 0000000000..da8cdfe9c0 --- /dev/null +++ b/test/JDBC/expected/babel_index_nulls_order-vu-prepare.out @@ -0,0 +1,78 @@ +CREATE TABLE babel_index_nulls_order_tbl (a INT, b VARCHAR(10)) +go + +INSERT INTO babel_index_nulls_order_tbl VALUES +(1, 'abc'), (2, 'def'), (3, 'ghi'), (4, 'jkl'), +(5, 'mno'), (6, 'pqr'), (7, 'stu'), (8, 'xyz'), +(1, 'abc'), (2, 'def'), (3, 'ghi'), (4, 'jkl'), +(5, 'mno'), (6, 'pqr'), (7, 'stu'), (8, 'xyz'), +(NULL, NULL) +go +~~ROW COUNT: 17~~ + + +CREATE INDEX babel_index_nulls_order_asc_idx_a ON babel_index_nulls_order_tbl (a ASC) +go +CREATE INDEX babel_index_nulls_order_desc_idx_b ON babel_index_nulls_order_tbl (b DESC) +go +CREATE INDEX babel_index_nulls_order_default_idx_ab ON babel_index_nulls_order_tbl (a, b) +go + +SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'babel_index_nulls_order_tbl' +ORDER BY indexname +go +~~START~~ +varchar#!#text +babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f#!#CREATE INDEX babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f ON master_dbo.babel_index_nulls_order_tbl USING btree (a NULLS FIRST) +babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93#!#CREATE INDEX babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93 ON master_dbo.babel_index_nulls_order_tbl USING btree (a NULLS FIRST, b NULLS FIRST) +babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac#!#CREATE INDEX babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac ON master_dbo.babel_index_nulls_order_tbl USING btree (b DESC NULLS LAST) +~~END~~ + + +CREATE VIEW babel_index_nulls_order_a_v1 AS +SELECT TOP 1 a FROM babel_index_nulls_order_tbl WHERE a <= 5 OR a IS NULL ORDER BY a DESC +go + +CREATE VIEW babel_index_nulls_order_a_v2 AS +SELECT TOP 1 a FROM babel_index_nulls_order_tbl WHERE a > 5 OR a IS NULL ORDER BY a ASC +go + +CREATE VIEW babel_index_nulls_order_a_v3 AS +SELECT TOP 1 a FROM babel_index_nulls_order_tbl WHERE a > 5 OR a IS NULL ORDER BY a +go + +CREATE VIEW babel_index_nulls_order_b_v1 AS +SELECT TOP 1 b FROM babel_index_nulls_order_tbl WHERE b <= 'sss' OR b IS NULL ORDER BY b DESC +go + +CREATE VIEW babel_index_nulls_order_b_v2 AS +SELECT TOP 1 b FROM babel_index_nulls_order_tbl WHERE b > 'sss' OR b IS NULL ORDER BY b ASC +go + +CREATE VIEW babel_index_nulls_order_b_v3 AS +SELECT TOP 1 b FROM babel_index_nulls_order_tbl WHERE b > 'sss' OR b IS NULL ORDER BY b +go + +CREATE VIEW babel_index_nulls_order_ab_v1 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a = 3 AND b <= 'sss') OR b IS NULL ORDER BY b DESC +go + +CREATE VIEW babel_index_nulls_order_ab_v2 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a = 3 AND b <= 'sss') OR b IS NULL ORDER BY b ASC +go + +CREATE VIEW babel_index_nulls_order_ab_v3 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a = 3 AND b <= 'sss') OR b IS NULL ORDER BY b +go + +CREATE VIEW babel_index_nulls_order_ab_v4 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a > 5 AND b = 'xyz') OR a IS NULL ORDER BY a DESC +go + +CREATE VIEW babel_index_nulls_order_ab_v5 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a > 5 AND b = 'xyz') OR a IS NULL ORDER BY a ASC +go + +CREATE VIEW babel_index_nulls_order_ab_v6 AS +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a > 5 AND b = 'xyz') OR a IS NULL ORDER BY a +go diff --git a/test/JDBC/expected/babel_index_nulls_order-vu-verify.out b/test/JDBC/expected/babel_index_nulls_order-vu-verify.out new file mode 100644 index 0000000000..58e9b9a7f9 --- /dev/null +++ b/test/JDBC/expected/babel_index_nulls_order-vu-verify.out @@ -0,0 +1,241 @@ +-- Nulls check +SELECT * FROM babel_index_nulls_order_a_v1 +go +~~START~~ +int +5 +~~END~~ + +SELECT * FROM babel_index_nulls_order_a_v2 +go +~~START~~ +int + +~~END~~ + +SELECT * FROM babel_index_nulls_order_a_v3 +go +~~START~~ +int + +~~END~~ + +SELECT * FROM babel_index_nulls_order_b_v1 +go +~~START~~ +varchar +pqr +~~END~~ + +SELECT * FROM babel_index_nulls_order_b_v2 +go +~~START~~ +varchar + +~~END~~ + +SELECT * FROM babel_index_nulls_order_b_v3 +go +~~START~~ +varchar + +~~END~~ + +SELECT * FROM babel_index_nulls_order_ab_v1 +go +~~START~~ +int#!#varchar +3#!#ghi +~~END~~ + +SELECT * FROM babel_index_nulls_order_ab_v2 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_ab_v3 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_ab_v4 +go +~~START~~ +int#!#varchar +8#!#xyz +~~END~~ + +SELECT * FROM babel_index_nulls_order_ab_v5 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + +SELECT * FROM babel_index_nulls_order_ab_v6 +go +~~START~~ +int#!#varchar +#!# +~~END~~ + + +-- Check query plans, all aggregations should be optimized +-- into LIMIT + index scan. +SELECT set_config('babelfishpg_tsql.enable_pg_hint', 'on', false) +go +~~START~~ +text +on +~~END~~ + +SELECT set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~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~~ + +SET babelfish_showplan_all ON +go + +SELECT TOP 1 a FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_asc_idx_a)) WHERE a <= 5 ORDER BY a DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f) */ TOP 1 a FROM babel_index_nulls_order_tbl WHERE a <= 5 ORDER BY a DESC +Limit + -> Index Scan Backward using babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f on babel_index_nulls_order_tbl + Index Cond: (a <= 5) +~~END~~ + +SELECT TOP 1 a FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_asc_idx_a)) WHERE a > 5 ORDER BY a ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f) */ TOP 1 a FROM babel_index_nulls_order_tbl WHERE a > 5 ORDER BY a ASC +Limit + -> Index Scan using babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f on babel_index_nulls_order_tbl + Index Cond: (a > 5) +~~END~~ + +SELECT TOP 1 a FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_asc_idx_a)) WHERE a > 5 ORDER BY a +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f) */ TOP 1 a FROM babel_index_nulls_order_tbl WHERE a > 5 ORDER BY a +Limit + -> Index Scan using babel_index_nulls_order_asc_idxe9daa5ef2b0c11acbc565480994a3b5f on babel_index_nulls_order_tbl + Index Cond: (a > 5) +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_desc_idx_b)) WHERE b <= 'sss' ORDER BY b DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac) */ TOP 1 b FROM babel_index_nulls_order_tbl WHERE b <= 'sss' ORDER BY b DESC +Limit + -> Index Scan using babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac on babel_index_nulls_order_tbl + Index Cond: (b <= 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_desc_idx_b)) WHERE b > 'sss' ORDER BY b ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac) */ TOP 1 b FROM babel_index_nulls_order_tbl WHERE b > 'sss' ORDER BY b ASC +Limit + -> Index Scan Backward using babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac on babel_index_nulls_order_tbl + Index Cond: (b > 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 b FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_desc_idx_b)) WHERE b > 'sss' ORDER BY b +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac) */ TOP 1 b FROM babel_index_nulls_order_tbl WHERE b > 'sss' ORDER BY b +Limit + -> Index Scan Backward using babel_index_nulls_order_desc_idd9c7b3b18a405e8210be834aac2207ac on babel_index_nulls_order_tbl + Index Cond: (b > 'sss'::"varchar") +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b DESC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93) */ TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b DESC +Limit + -> Index Scan Backward using babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93 on babel_index_nulls_order_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b ASC +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93) */ TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b ASC +Limit + -> Index Scan using babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93 on babel_index_nulls_order_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + +SELECT TOP 1 a, b FROM babel_index_nulls_order_tbl WITH (INDEX (babel_index_nulls_order_default_idx_ab)) WHERE (a = 3 AND b <= 'sss') ORDER BY b +go +~~START~~ +text +Query Text: SELECT/*+ indexscan(babel_index_nulls_order_tbl babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93) */ TOP 1 a, b FROM babel_index_nulls_order_tbl WHERE (a = 3 AND b <= 'sss') ORDER BY b +Limit + -> Index Scan using babel_index_nulls_order_default36696f80588c2802b7570cf53f8a7d93 on babel_index_nulls_order_tbl + Index Cond: ((a = 3) AND (b <= 'sss'::"varchar")) +~~END~~ + + +-- Reset +SET babelfish_showplan_all OFF +go +SELECT set_config('babelfishpg_tsql.enable_pg_hint', 'off', false) +go +~~START~~ +text +off +~~END~~ + +SELECT set_config('babelfishpg_tsql.explain_costs', 'on', false) +go +~~START~~ +text +on +~~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~~ + diff --git a/test/JDBC/expected/babel_int4_varbinary_div-vu-cleanup.out b/test/JDBC/expected/babel_int4_varbinary_div-vu-cleanup.out new file mode 100644 index 0000000000..ec5edfd144 --- /dev/null +++ b/test/JDBC/expected/babel_int4_varbinary_div-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_int4_varbinary_vu_prepare_view +GO + +DROP PROC sys_int4_varbinary_vu_prepare_proc +GO + +DROP FUNCTION sys_int4_varbinary_vu_prepare_func() +GO diff --git a/test/JDBC/expected/babel_int4_varbinary_div-vu-prepare.out b/test/JDBC/expected/babel_int4_varbinary_div-vu-prepare.out new file mode 100644 index 0000000000..c67dd28c4a --- /dev/null +++ b/test/JDBC/expected/babel_int4_varbinary_div-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_int4_varbinary_vu_prepare_view AS +SELECT (23446576 / CAST(12345 AS varbinary(4))) +GO + +CREATE PROC sys_int4_varbinary_vu_prepare_proc AS +Select (21745678/CAST(424748 as varbinary(4))) +GO + +CREATE FUNCTION sys_int4_varbinary_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (select 254354 / 0) +END +GO diff --git a/test/JDBC/expected/babel_int4_varbinary_div-vu-verify.out b/test/JDBC/expected/babel_int4_varbinary_div-vu-verify.out new file mode 100644 index 0000000000..9b16892ff9 --- /dev/null +++ b/test/JDBC/expected/babel_int4_varbinary_div-vu-verify.out @@ -0,0 +1,27 @@ +USE master +GO + +SELECT * FROM sys_int4_varbinary_vu_prepare_view +GO +~~START~~ +int +1899 +~~END~~ + + +EXEC sys_int4_varbinary_vu_prepare_proc +GO +~~START~~ +int +51 +~~END~~ + + +SELECT sys_int4_varbinary_vu_prepare_func() +GO +~~START~~ +int +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + 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_operators.out b/test/JDBC/expected/babel_operators.out index 188153324d..e515115a25 100644 --- a/test/JDBC/expected/babel_operators.out +++ b/test/JDBC/expected/babel_operators.out @@ -3,12 +3,12 @@ SELECT (123 + 0x42); SELECT (0x42 + 123); GO ~~START~~ -bigint +int 189 ~~END~~ ~~START~~ -bigint +int 189 ~~END~~ @@ -18,12 +18,12 @@ SELECT (123 - 0x42); SELECT (0x42 - 123); GO ~~START~~ -bigint +int 57 ~~END~~ ~~START~~ -bigint +int -57 ~~END~~ @@ -33,12 +33,12 @@ SELECT (123 * CAST(123 AS varbinary(4))); SELECT (CAST(123 AS varbinary(4)) * 123); GO ~~START~~ -bigint +int 15129 ~~END~~ ~~START~~ -bigint +int 15129 ~~END~~ @@ -48,12 +48,12 @@ SELECT (12345 / CAST(12 AS varbinary(4))); SELECT (CAST(12345 AS varbinary(4)) / 12); GO ~~START~~ -bigint +int 1028 ~~END~~ ~~START~~ -bigint +int 1028 ~~END~~ 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/babel_output_in_dml.out b/test/JDBC/expected/babel_output_in_dml.out index 67c332a0ac..5af6fedf5f 100644 --- a/test/JDBC/expected/babel_output_in_dml.out +++ b/test/JDBC/expected/babel_output_in_dml.out @@ -1513,7 +1513,7 @@ go -- delete with top -delete top 2 t1 +delete top (2) t1 output deleted.* into t2 where num<5; go @@ -1542,7 +1542,7 @@ int#!#varchar -- delete with top in subquery delete t1 output deleted.num, deleted.word into t2 -from (select top 2 * from t1 order by num asc) as x +from (select top (2) * from t1 order by num asc) as x where t1.num = x.num and t1.num<5; go ~~ROW COUNT: 2~~ @@ -2028,3 +2028,144 @@ go DROP TABLE #t2; go + +-- BABEL-4199 DELETE, join, and output +CREATE TABLE babel4199_t1(c1 varchar(30), c2 varchar(50)); +CREATE TABLE babel4199_t2(c1 varchar(30), c2 varchar(50)); +INSERT INTO babel4199_t1 VALUES ('1', '2'), ('2', '3'); +INSERT INTO babel4199_t2 VALUES ('1', '10'), ('-1', '100'); +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + + +BEGIN TRANSACTION + DELETE TOP(1) a OUTPUT b.* FROM babel4199_t1 a + JOIN babel4199_t2 b on a.c1 = b.c1 + WHERE a.c1 IN ( + SELECT TOP(5) c1 + FROM babel4199_t1 a + ORDER BY c2 + ) +ROLLBACK +GO +~~START~~ +varchar#!#varchar +1#!#10 +~~END~~ + + +BEGIN TRANSACTION + DELETE a output b.* + from babel4199_t1 a + join babel4199_t2 b on a.c1 = b.c1 + where a.c1 = 1 +ROLLBACK +GO +~~START~~ +varchar#!#varchar +1#!#10 +~~END~~ + + +BEGIN TRANSACTION + DELETE babel4199_t1 output b.* + from babel4199_t1 a + join babel4199_t2 b on a.c1 = b.c1 + where a.c1 = 1 +ROLLBACK +GO +~~START~~ +varchar#!#varchar +1#!#10 +~~END~~ + + +-- Is an error in T-SQL +BEGIN TRANSACTION + DELETE a output a.* + from babel4199_t1 a + join babel4199_t2 b on a.c1 = b.c1 + where a.c1 = 1 +ROLLBACK +GO +~~START~~ +varchar#!#varchar +1#!#2 +~~END~~ + + +-- Should error +BEGIN TRANSACTION + DELETE babel4199_t1 output babel4199_t1.* + from babel4199_t1 a + join babel4199_t2 b on a.c1 = b.c1 + where a.c1 = 1 +ROLLBACK +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid reference to FROM-clause entry for table "babel4199_t1")~~ + + +BEGIN TRANSACTION + DELETE a output deleted.* + from babel4199_t1 a + join babel4199_t2 b on a.c1 = b.c1 + where a.c1 = 1 +ROLLBACK +GO +~~START~~ +varchar#!#varchar +1#!#2 +~~END~~ + + +BEGIN TRANSACTION + DELETE a output deleted.c1, deleted.c2 + from babel4199_t1 a + join babel4199_t2 b on a.c1 = b.c1 + where a.c1 = 1 +ROLLBACK +GO +~~START~~ +varchar#!#varchar +1#!#2 +~~END~~ + + + +DROP TABLE babel4199_t1 +DROP TABLE babel4199_t2 +GO + +-- BABEL-1633 +create table deleted(num integer, nextnum integer); +insert into deleted values(10, 11); +GO +~~ROW COUNT: 1~~ + + +create table babel1633(num integer, word varchar(10)); +insert into babel1633 values(10, 'ten'); +GO +~~ROW COUNT: 1~~ + + +DELETE deleted + OUTPUT babel1633.word +FROM deleted +INNER JOIN babel1633 + ON deleted.num=babel1633.num +WHERE babel1633.num=10; +GO +~~START~~ +varchar +ten +~~END~~ + + +drop table deleted; +drop table babel1633; +GO 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/test/JDBC/expected/babel_smalldatetime.out b/test/JDBC/expected/babel_smalldatetime.out index a0db023e2c..46224c22a2 100644 --- a/test/JDBC/expected/babel_smalldatetime.out +++ b/test/JDBC/expected/babel_smalldatetime.out @@ -149,22 +149,22 @@ smalldatetime ~~START~~ smalldatetime -1980-07-08 15:59:00.0 +1980-07-08 23:59:00.0 ~~END~~ ~~START~~ smalldatetime -2010-07-08 15:59:00.0 +2010-07-08 23:59:00.0 ~~END~~ ~~START~~ smalldatetime -1980-07-09 07:59:00.0 +1980-07-08 23:59:00.0 ~~END~~ ~~START~~ smalldatetime -2010-07-09 07:59:00.0 +2010-07-08 23:59:00.0 ~~END~~ -- Cast from smalldatetime @@ -289,11 +289,6 @@ smalldatetime 1900-01-01 00:00:00.0 ~~END~~ -~~START~~ -smalldatetime -2079-06-06 23:00:00.0 -~~END~~ - ~~ERROR (Code: 33557097)~~ ~~ERROR (Message: data out of range for smalldatetime)~~ @@ -377,9 +372,19 @@ text May ~~END~~ +~~START~~ +smalldatetime +2016-12-26 23:30:00.0 +~~END~~ + +~~START~~ +smalldatetime +2016-12-27 00:25:00.0 +~~END~~ + ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: operator is not unique: smalldatetime + interval)~~ +~~ERROR (Message: data out of range for smalldatetime)~~ -- Clean up diff --git a/test/JDBC/expected/babel_smalldatetime_before_15-5.out b/test/JDBC/expected/babel_smalldatetime_before_15-5.out new file mode 100644 index 0000000000..9e3dd9dd9c --- /dev/null +++ b/test/JDBC/expected/babel_smalldatetime_before_15-5.out @@ -0,0 +1,383 @@ +-- Testing rounding behaviour when inserting into the table +create table smalldatetime_testing ( sm smalldatetime ); +INSERT INTO smalldatetime_testing VALUES('23:40:29.998'); +INSERT INTO smalldatetime_testing VALUES('1992-05-23 23:40:29.998'); +INSERT INTO smalldatetime_testing VALUES('1992-05-23 23:40:29.998'); +INSERT INTO smalldatetime_testing VALUES('1992-05-23 23:40:29.999'); +INSERT INTO smalldatetime_testing VALUES('1992-05-23 23:40:30.000'); +INSERT INTO smalldatetime_testing VALUES('2002-05-23 23:41:29.998'); +INSERT INTO smalldatetime_testing VALUES('2002-05-23 23:41:29.999'); +INSERT INTO smalldatetime_testing VALUES('2002-05-23 23:41:30.000'); +INSERT INTO smalldatetime_testing VALUES('2000-01-01 00:00:29.998'); +INSERT INTO smalldatetime_testing VALUES('2000-01-01 00:00:29.999'); +INSERT INTO smalldatetime_testing VALUES('1999-12-31 23:59:30.000'); +INSERT INTO smalldatetime_testing VALUES('1999-12-31 23:59:29.999'); +INSERT INTO smalldatetime_testing VALUES('1999-12-31 23:59:29.998'); +select * from smalldatetime_testing; +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~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +smalldatetime +1900-01-01 23:40:00.0 +1992-05-23 23:40:00.0 +1992-05-23 23:40:00.0 +1992-05-23 23:41:00.0 +1992-05-23 23:41:00.0 +2002-05-23 23:41:00.0 +2002-05-23 23:42:00.0 +2002-05-23 23:42:00.0 +2000-01-01 00:00:00.0 +2000-01-01 00:01:00.0 +2000-01-01 00:00:00.0 +2000-01-01 00:00:00.0 +1999-12-31 23:59:00.0 +~~END~~ + + +-- Test comparision with datetime/smalldatetime/date +select * from smalldatetime_testing where sm >= cast('2000-01-01 00:00:59' as smalldatetime); +select * from smalldatetime_testing where sm >= cast('1992-05-23 23:40:00' as datetime) + and sm < cast('1992-05-23 23:41:00' as datetime); +select * from smalldatetime_testing where sm < cast(cast('1992-05-24' as date) as smalldatetime); +go +~~START~~ +smalldatetime +2002-05-23 23:41:00.0 +2002-05-23 23:42:00.0 +2002-05-23 23:42:00.0 +2000-01-01 00:01:00.0 +~~END~~ + +~~START~~ +smalldatetime +1992-05-23 23:40:00.0 +1992-05-23 23:40:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 23:40:00.0 +1992-05-23 23:40:00.0 +1992-05-23 23:40:00.0 +1992-05-23 23:41:00.0 +1992-05-23 23:41:00.0 +~~END~~ + + +-- Test rounding for 23:59:59 +SELECT CAST('1992-05-09 23:59:59' AS SMALLDATETIME); +SELECT CAST('2002-05-09 23:59:59' AS SMALLDATETIME); +SELECT CAST('1999-12-31 23:59:59' AS SMALLDATETIME); +go +~~START~~ +smalldatetime +1992-05-10 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2002-05-10 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2000-01-01 00:00:00.0 +~~END~~ + + +-- Test type cast to/from other time formats +-- Cast to smalldatetime +select CAST(CAST('00:00:00.234' AS time) AS smalldatetime); +select CAST(CAST('01:02:03.456' AS time) AS smalldatetime); +select CAST(CAST('2020-03-15' AS date) AS smalldatetime); +select CAST(CAST('2020-03-15' AS datetime) AS smalldatetime); +select CAST(CAST('2010-07-08 23:59:29.998' AS datetime) AS smalldatetime); +select CAST(CAST('1980-07-08 23:59:29.123456 +8:00' AS datetimeoffset) AS smalldatetime); +select CAST(CAST('2010-07-08 23:59:29.123456 +8:00' AS datetimeoffset) AS smalldatetime); +select CAST(CAST('1980-07-08 23:59:29.123456 -8:00' AS datetimeoffset) AS smalldatetime); +select CAST(CAST('2010-07-08 23:59:29.123456 -8:00' AS datetimeoffset) AS smalldatetime); +go +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 01:02:00.0 +~~END~~ + +~~START~~ +smalldatetime +2020-03-15 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2020-03-15 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2010-07-08 23:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +1980-07-08 23:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +2010-07-08 23:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +1980-07-08 23:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +2010-07-08 23:59:00.0 +~~END~~ + +-- Cast from smalldatetime +select CAST(CAST('2010-07-08' AS smalldatetime) AS time); +select CAST(CAST('2010-07-08 23:59:29.998' AS smalldatetime) AS time); +select CAST(CAST('2010-07-08 23:59:31.998' AS smalldatetime) AS time); +select CAST(CAST('1980-07-08 23:59:29.998' AS smalldatetime) AS time); +select CAST(CAST('1980-07-08 23:59:31.998' AS smalldatetime) AS time); +select CAST(CAST('2020-03-15' AS smalldatetime) AS date); +select CAST(CAST('2010-07-08 23:59:29.998' AS smalldatetime) AS date); +select CAST(CAST('2010-07-08 23:59:30.000' AS smalldatetime) AS date); +select CAST(CAST('2010-07-08 23:59:29.998' AS smalldatetime) AS datetime); +select CAST(CAST('1992-07-08 23:59:29.998' AS smalldatetime) AS datetime); +select CAST(CAST('2010-07-08 23:59:29.998' AS smalldatetime) AS datetimeoffset); +select CAST(CAST('1990-07-08 23:59:29.998' AS smalldatetime) AS datetimeoffset); +go +~~START~~ +time +00:00:00.0000000 +~~END~~ + +~~START~~ +time +23:59:00.0000000 +~~END~~ + +~~START~~ +time +00:00:00.0000000 +~~END~~ + +~~START~~ +time +23:59:00.0000000 +~~END~~ + +~~START~~ +time +00:00:00.0000000 +~~END~~ + +~~START~~ +date +2020-03-15 +~~END~~ + +~~START~~ +date +2010-07-08 +~~END~~ + +~~START~~ +date +2010-07-09 +~~END~~ + +~~START~~ +datetime +2010-07-08 23:59:00.0 +~~END~~ + +~~START~~ +datetime +1992-07-08 23:59:00.0 +~~END~~ + +~~START~~ +datetimeoffset +2010-07-08 23:59:00.0000000 +00:00 +~~END~~ + +~~START~~ +datetimeoffset +1990-07-08 23:59:00.0000000 +00:00 +~~END~~ + + +-- Test smalldatetime value ranges +select cast('1900-01-01' as smalldatetime); +select cast('2079-06-06' as smalldatetime); +select cast('1899-12-31 23:59:29.999' as smalldatetime); +select cast('2079-06-06 23:59:29.998' as smalldatetime); +select CAST(CAST('1899-12-31 23:59:30.000' AS datetime) AS smalldatetime); +select CAST(CAST('1899-12-31 23:59:30.000 +0:00' AS datetimeoffset) AS smalldatetime); +select CAST(CAST('2079-06-06 23:59:30.000 +1:00' AS datetimeoffset) AS smalldatetime); +select cast('1899-12-31' as smalldatetime); -- out of range +select cast('2079-06-07' as smalldatetime); -- out of range +select cast('2079-06-06 23:59:29.999' as smalldatetime); -- out of range +select CAST(CAST('2099-03-15' AS date) AS smalldatetime); -- out of range +select CAST(CAST('1800-03-15 23:59:29.998' AS datetime) AS smalldatetime);-- out of range +select CAST(CAST('2099-03-15 23:59:29.998' AS datetime) AS smalldatetime);-- out of range +select CAST(CAST('1899-12-31 23:59:30.000 +1:00' AS datetimeoffset) AS smalldatetime);-- out of range +select CAST(CAST('2099-03-15 23:59:29.998 +6:00' AS datetimeoffset) AS smalldatetime);-- out of range +go +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2079-06-06 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +2079-06-06 23:59:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: data out of range for smalldatetime)~~ + + +-- Test smalldatetime default value +create table t1 (a smalldatetime, b int); +insert into t1 (b) values (1); +select a from t1 where b = 1; +go +~~ROW COUNT: 1~~ + +~~START~~ +smalldatetime + +~~END~~ + + +-- Test smalldatetime as parameter for time related functions +select day(cast('2002-05-23 23:41:29.998' as smalldatetime)); +select month(cast('2002-05-23 23:41:29.998' as smalldatetime)); +select year(cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datepart(quarter, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datepart(hour, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datepart(dayofyear, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datepart(second, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datename(year, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datename(dw, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select datename(month, cast('2002-05-23 23:41:29.998' as smalldatetime)); +select dateadd(second, 56, cast('2016-12-26 23:29:29' as smalldatetime)); +select dateadd(minute, 56, cast('2016-12-26 23:29:29' as smalldatetime)); +select dateadd(year, 150, cast('2016-12-26 23:29:29' as smalldatetime)); -- Expect error +go +~~START~~ +int +23 +~~END~~ + +~~START~~ +int +5 +~~END~~ + +~~START~~ +int +2002 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +int +23 +~~END~~ + +~~START~~ +int +143 +~~END~~ + +~~START~~ +int +0 +~~END~~ + +~~START~~ +text +2002 +~~END~~ + +~~START~~ +text +Thursday +~~END~~ + +~~START~~ +text +May +~~END~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: operator is not unique: smalldatetime + interval)~~ + + +-- Clean up +drop table smalldatetime_testing; +drop table t1; +go 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_top_in_dml.out b/test/JDBC/expected/babel_top_in_dml.out index 963dd566c2..60b22331c0 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,1143 @@ 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_top_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~~ + + +-- Should fail +BEGIN TRAN +UPDATE top(1) t1 SET a = t1.a + 1 +OUTPUT deleted.* +FROM non_existant_tbl t1 +ROLLBACK +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "non_existant_tbl" does not exist)~~ + + +-- 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~~ + + +BEGIN TRAN +UPDATE top(1) t1 SET t1.a = t1.a + 1 +OUTPUT inserted.* +FROM babel_update_tbl1 t1 +INNER JOIN babel_update_tbl1 t2 +ON t1.b = t2.b +ROLLBACK +go +~~START~~ +int#!#varchar +2#!#left +~~END~~ + + +-- 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_top_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_top_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~~ + + +exec babel_2020_delete_ct; +delete top(2) babel_2020_delete_t1 output deleted.* +from babel_2020_delete_t1 x join babel_2020_delete_t2 y on y.a = 2; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~START~~ +int +1 +2 +~~END~~ + + +-- 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~~ + + +exec babel_2020_delete_ct; +delete top(1) babel_2020_delete_t1 output deleted.* +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~~ + +~~START~~ +int +1 +~~END~~ + + +-- 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_top_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_top_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_top_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 + +-- TOP with OUTPUT & OUTPUT INTO w/out JOIN +create table top_with_output_tbl(no_o_id int, no_w_id VARCHAR(20)) +go + +insert into top_with_output_tbl VALUES (-1, 'foo'), (2, 'foo'); +go +~~ROW COUNT: 2~~ + + +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +set babelfish_showplan_all on +go + +UPDATE TOP (1) dbo.top_with_output_tbl SET no_o_id = 100 +OUTPUT deleted.no_o_id, inserted.no_o_id +WHERE top_with_output_tbl.no_w_id = 'foo' +GO +~~START~~ +int#!#int +~~END~~ + +~~START~~ +text +Query Text: UPDATE TOP (1) dbo.top_with_output_tbl SET no_o_id = 100 +OUTPUT deleted.no_o_id, inserted.no_o_id +WHERE top_with_output_tbl.no_w_id = 'foo' +Update on top_with_output_tbl + -> Limit + -> Nested Loop + -> Seq Scan on top_with_output_tbl + Filter: (no_w_id = 'foo'::"varchar") + -> Tid Scan on top_with_output_tbl deleted + TID Cond: (ctid = top_with_output_tbl.ctid) +~~END~~ + + +DELETE TOP (1) +FROM top_with_output_tbl +OUTPUT deleted.no_o_id +WHERE top_with_output_tbl.no_w_id = 'foo' +GO +~~START~~ +int +~~END~~ + +~~START~~ +text +Query Text: DELETE TOP (1) +FROM top_with_output_tbl +OUTPUT deleted.no_o_id +WHERE top_with_output_tbl.no_w_id = 'foo' +Delete on top_with_output_tbl + -> Limit + -> Seq Scan on top_with_output_tbl + Filter: (no_w_id = 'foo'::"varchar") +~~END~~ + + +set babelfish_showplan_all off +go + +select set_config('babelfishpg_tsql.explain_costs', 'on', false) +go +~~START~~ +text +on +~~END~~ + + + + +declare @t_out table (no_o_id int); +UPDATE TOP (1) dbo.top_with_output_tbl SET no_o_id = 10 +OUTPUT deleted.no_o_id INTO @t_out +WHERE top_with_output_tbl.no_w_id = 'foo' +select * from @t_out; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +-1 +~~END~~ + + +UPDATE TOP (1) dbo.top_with_output_tbl SET no_o_id = 100 +OUTPUT deleted.no_o_id, inserted.no_o_id +WHERE top_with_output_tbl.no_w_id = 'foo' +GO +~~START~~ +int#!#int +2#!#100 +~~END~~ + + + + +declare @t_out table (no_o_id int); +DELETE TOP (1) +FROM dbo.top_with_output_tbl +OUTPUT deleted.no_o_id INTO @t_out +WHERE top_with_output_tbl.no_w_id = 'foo' +select * from @t_out; +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +10 +~~END~~ + + +DELETE TOP (1) +FROM dbo.top_with_output_tbl +OUTPUT deleted.no_o_id +WHERE top_with_output_tbl.no_w_id = 'foo' +GO +~~START~~ +int +100 +~~END~~ + + +drop table top_with_output_tbl; +go + +-- BABEL-2007 +CREATE TABLE babel2007_t1(c1PK INT PRIMARY KEY, c2INT INT, c4COMMENT VARCHAR(100)) +CREATE TABLE babel2007_t2(c1PK INT PRIMARY KEY, c2INT INT, c4COMMENT VARCHAR(100)) +GO + +INSERT INTO babel2007_t1 VALUES( 1, 10, 'insert' ) + , ( 2, 20, 'insert' ) + , ( 3, 30, 'insert' ) + , ( 4, 40, 'insert' ) +GO +~~ROW COUNT: 4~~ + + +INSERT INTO babel2007_t2 VALUES( 1, 10, 'insert' ) + , ( 2, 20, 'insert' ) + , ( 3, 30, 'insert' ) + , ( 4, 40, 'insert' ) +GO +~~ROW COUNT: 4~~ + + +UPDATE top(2) babel2007_t1 +SET c4COMMENT = 'updated: TOP (2), output to client' +OUTPUT INSERTED.*, DELETED.* +FROM babel2007_t1 INNER JOIN babel2007_t2 ON ( babel2007_t1.c2INT = babel2007_t2.c2INT ) +WHERE babel2007_t2.c1PK <= 5 +GO +~~START~~ +int#!#int#!#varchar#!#int#!#int#!#varchar +1#!#10#!#updated: TOP (2), output to client#!#1#!#10#!#insert +2#!#20#!#updated: TOP (2), output to client#!#2#!#20#!#insert +~~END~~ + + +DELETE top(2) babel2007_t1 +OUTPUT DELETED.* +FROM babel2007_t1 INNER JOIN babel2007_t2 ON ( babel2007_t1.c2INT = babel2007_t2.c2INT ) +WHERE babel2007_t2.c1PK <= 5 +GO +~~START~~ +int#!#int#!#varchar +1#!#10#!#updated: TOP (2), output to client +2#!#20#!#updated: TOP (2), output to client +~~END~~ + + +DROP TABLE babel2007_t1 +DROP TABLE babel2007_t2 +GO diff --git a/test/JDBC/expected/babel_transaction.out b/test/JDBC/expected/babel_transaction.out new file mode 100644 index 0000000000..b2adb22031 --- /dev/null +++ b/test/JDBC/expected/babel_transaction.out @@ -0,0 +1,484 @@ +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; +set transaction isolation level read uncommitted; +select @@trancount; +begin tran; +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~~ + + +-- 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/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/test/JDBC/expected/babel_varbinary.out b/test/JDBC/expected/babel_varbinary.out index 568ec8c8ee..70e770fb42 100644 --- a/test/JDBC/expected/babel_varbinary.out +++ b/test/JDBC/expected/babel_varbinary.out @@ -124,28 +124,28 @@ int select 0x1F * 10; go ~~START~~ -bigint +int 310 ~~END~~ select 10 * 0x1F; go ~~START~~ -bigint +int 310 ~~END~~ select 0x1F / 10; go ~~START~~ -bigint +int 3 ~~END~~ select 100 / 0x1F; go ~~START~~ -bigint +int 3 ~~END~~ @@ -164,6 +164,438 @@ go ~~ERROR (Message: division by zero)~~ +--division between varbinary and int4 datatype, vice-versa +Select 100 / 0x +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +Select 256 / 0x10 +go +~~START~~ +int +16 +~~END~~ + +Select 56457 / 0x82B0 +go +~~START~~ +int +1 +~~END~~ + +Select 243534536 / 0x45A32D +go +~~START~~ +int +53 +~~END~~ + +select @@microsoftversion / 0x1000000 +go +~~START~~ +int +12 +~~END~~ + +Select 2147483647 / 0x7FFFFFFF +go +~~START~~ +int +1 +~~END~~ + +Select 2147483647 / 0x80000000 +go +~~START~~ +int +0 +~~END~~ + +Select 2147483647 / 0x80000001 +go +~~START~~ +int +-1 +~~END~~ + +Select 2147483647 / 0xC0000005 +go +~~START~~ +int +-2 +~~END~~ + +Select -2147483647 / 0xC0000005 +go +~~START~~ +int +2 +~~END~~ + +Select -2147483648 / 0xC0000005 +go +~~START~~ +int +2 +~~END~~ + +SELECT (12345 / CAST(12 AS varbinary(4))) +go +~~START~~ +int +1028 +~~END~~ + +Select (cast(0x100 as int) / 0x10) +go +~~START~~ +int +16 +~~END~~ + +Select cast(0x100 as int)/cast(2345 as varbinary) +go +~~START~~ +int +0 +~~END~~ + +create table int4var(a varbinary,b int) +go +insert into int4var values (0x23 , 2147563) +go +~~ROW COUNT: 1~~ + +insert into int4var values (0xFF ,-2147483647 ) +go +~~ROW COUNT: 1~~ + +Select b/a from int4var +go +~~START~~ +int +61358 +-8421504 +~~END~~ + +Select cast(b as int)/a from int4var +go +~~START~~ +int +61358 +-8421504 +~~END~~ + +Select (12345+3543647)/cast((543210 & CAST(12345 AS varbinary(4))) as varbinary) +go +~~START~~ +int +88899 +~~END~~ + +Select (sys.isdate('2023-4-5')*34+64)/0x234 +go +~~START~~ +int +0 +~~END~~ + +Select (sys.isdate('2023-4-5')*34+64)/cast(sys.isdate('2023-4-5') as varbinary) +go +~~START~~ +int +98 +~~END~~ + +Select cast((0x234 & 23) as int) / cast(sys.isdate('2023-4-5') as varbinary) +go +~~START~~ +int +20 +~~END~~ + +Select cast(0x4567 as int)/cast((543210 & CAST(12345 AS varbinary(4))) as varbinary(4)) +go +~~START~~ +int +444 +~~END~~ + +select 123 / 0x00 +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +select 0 / 0x00 +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +select 424748364 / 0x101 +go +~~START~~ +int +1652717 +~~END~~ + +select -424748364 / 0x101 +go +~~START~~ +int +-1652717 +~~END~~ + + +Select 0x/100 +go +~~START~~ +int +0 +~~END~~ + +Select 0x10 / 2 +go +~~START~~ +int +8 +~~END~~ + +Select 0x82B0 / 3 +go +~~START~~ +int +11152 +~~END~~ + +Select 0x45A32D / 4 +go +~~START~~ +int +1140939 +~~END~~ + +select 0x1000000 / @@microsoftversion +go +~~START~~ +int +0 +~~END~~ + +Select 0x7FFFFFFF / 2147483647 +go +~~START~~ +int +1 +~~END~~ + +Select 0x80000000 / 2147483647 +go +~~START~~ +int +-1 +~~END~~ + +Select 0x80000001 / 2147483647 +go +~~START~~ +int +-1 +~~END~~ + +Select 0xC0000005 / 2147483647 +go +~~START~~ +int +0 +~~END~~ + +Select 0xC0000005 / -2147483647 +go +~~START~~ +int +0 +~~END~~ + +Select 0xC0000005 / -2147483648 +go +~~START~~ +int +0 +~~END~~ + +SELECT (CAST(123456 AS varbinary(4)) / 1234) +go +~~START~~ +int +100 +~~END~~ + +Select (0x1110 / cast(0x100 as int) ) +go +~~START~~ +int +17 +~~END~~ + +Select cast(0x1234 as varbinary) / cast(0x100 as int) +go +~~START~~ +int +18 +~~END~~ + +Select a/b from int4var +go +~~START~~ +int +0 +0 +~~END~~ + +Select a/cast(b as int) from int4var +go +~~START~~ +int +0 +0 +~~END~~ + +Select cast((5432105 & CAST(12345 AS varbinary(4)))as varbinary)/(12345+3543647) +go +~~START~~ +int +0 +~~END~~ + +Select cast((54321 & CAST(12345 AS varbinary(4))) as varbinary)/cast(0x4567 as int) +go +~~START~~ +int +0 +~~END~~ + +Select 0x23FF/sys.isdate('2023-4-5') +go +~~START~~ +int +9215 +~~END~~ + +Select 0x233DF/(sys.isdate('2023-4-5')*34+64) +go +~~START~~ +int +1472 +~~END~~ + +Select cast(sys.isdate('2023-4-5') as varbinary)/(sys.isdate('2023-4-5')*3+6) +go +~~START~~ +int +0 +~~END~~ + +Select cast(sys.isdate('2023-4-5') as varbinary)/cast((0x234 & 23) as int) +go +~~START~~ +int +0 +~~END~~ + +select 0x101 / 0 +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +select 0x00 / 0 +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +select 0x404 / 424748364 +go +~~START~~ +int +0 +~~END~~ + +select 0x404 / -424748364 +go +~~START~~ +int +0 +~~END~~ + + +-- testcases with binary for division operator between varbinary and int4 datatype, vice-versa +-- TODO :- Update the following test once the fix for BABEL-4308 is available +select cast(cast(NULL as binary) as int)/0x10 +go +~~START~~ +int + +~~END~~ + +select 0x100/cast(cast(NULL as binary) as int) +go +~~START~~ +int + +~~END~~ + +Select cast(cast(2147483648 as binary) as int) / 0x100 +go +~~START~~ +int +-8388608 +~~END~~ + +Select 0x100/cast(cast(2147483648 as binary) as int) +go +~~START~~ +int +0 +~~END~~ + +Select 100000000/cast(cast(2147483648 as binary) as varbinary) +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +Select cast(cast(2147483648 as binary) as varbinary) /1000000 +go +~~START~~ +int +0 +~~END~~ + +Select 100000000/cast(cast(-2147483649 as binary) as varbinary) +go +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + +Select cast(cast(-2147483649 as binary) as varbinary) /1000000 +go +~~START~~ +int +0 +~~END~~ + + +drop table int4var +go + + + + -- test hex string in procedure create procedure test_hex_bitop as begin diff --git a/test/JDBC/expected/babel_varbinary_int4_div-vu-cleanup.out b/test/JDBC/expected/babel_varbinary_int4_div-vu-cleanup.out new file mode 100644 index 0000000000..23ffe7f1f4 --- /dev/null +++ b/test/JDBC/expected/babel_varbinary_int4_div-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_varbinary_int4_vu_prepare_view +GO + +DROP PROC sys_varbinary_int4_vu_prepare_proc +GO + +DROP FUNCTION sys_varbinary_int4_vu_prepare_func() +GO diff --git a/test/JDBC/expected/babel_varbinary_int4_div-vu-prepare.out b/test/JDBC/expected/babel_varbinary_int4_div-vu-prepare.out new file mode 100644 index 0000000000..9bc8c64951 --- /dev/null +++ b/test/JDBC/expected/babel_varbinary_int4_div-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_varbinary_int4_vu_prepare_view AS +SELECT (CAST(12345 AS varbinary(4)) / 12) +GO + +CREATE PROC sys_varbinary_int4_vu_prepare_proc AS +Select (CAST(424748364 as varbinary(4)) / 13) +GO + +CREATE FUNCTION sys_varbinary_int4_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (select 0x101 / 0) +END +GO diff --git a/test/JDBC/expected/babel_varbinary_int4_div-vu-verify.out b/test/JDBC/expected/babel_varbinary_int4_div-vu-verify.out new file mode 100644 index 0000000000..c6b9ef78a0 --- /dev/null +++ b/test/JDBC/expected/babel_varbinary_int4_div-vu-verify.out @@ -0,0 +1,27 @@ +USE master +GO + +SELECT * FROM sys_varbinary_int4_vu_prepare_view +GO +~~START~~ +int +1028 +~~END~~ + + +EXEC sys_varbinary_int4_vu_prepare_proc +GO +~~START~~ +int +32672951 +~~END~~ + + +SELECT sys_varbinary_int4_vu_prepare_func() +GO +~~START~~ +int +~~ERROR (Code: 8134)~~ + +~~ERROR (Message: division by zero)~~ + diff --git a/test/JDBC/expected/babelfish_integrity_checker-vu-verify.out b/test/JDBC/expected/babelfish_integrity_checker-vu-verify.out index 4db2b355d9..6e2dd8826b 100644 --- a/test/JDBC/expected/babelfish_integrity_checker-vu-verify.out +++ b/test/JDBC/expected/babelfish_integrity_checker-vu-verify.out @@ -33,8 +33,10 @@ babelfish_authid_login_ext babelfish_authid_user_ext babelfish_db_seq babelfish_domain_mapping +babelfish_extended_properties babelfish_function_ext babelfish_namespace_ext +babelfish_server_options babelfish_sysdatabases babelfish_view_def ~~END~~ diff --git a/test/JDBC/expected/cast_eliminate-vu-cleanup.out b/test/JDBC/expected/cast_eliminate-vu-cleanup.out new file mode 100644 index 0000000000..2b03d077b7 --- /dev/null +++ b/test/JDBC/expected/cast_eliminate-vu-cleanup.out @@ -0,0 +1,5 @@ +drop table cast_eliminate +GO + +drop table cast_eliminate2 +GO diff --git a/test/JDBC/expected/cast_eliminate-vu-prepare.out b/test/JDBC/expected/cast_eliminate-vu-prepare.out new file mode 100644 index 0000000000..9a843e3766 --- /dev/null +++ b/test/JDBC/expected/cast_eliminate-vu-prepare.out @@ -0,0 +1,6 @@ +CREATE TABLE cast_eliminate( [ROID] [int] NOT NULL PRIMARY KEY ); +GO + +CREATE TABLE cast_eliminate2( [ROID] [bigint] NOT NULL PRIMARY KEY ); +GO + diff --git a/test/JDBC/expected/cast_eliminate-vu-verify.out b/test/JDBC/expected/cast_eliminate-vu-verify.out new file mode 100644 index 0000000000..3f75d09b0d --- /dev/null +++ b/test/JDBC/expected/cast_eliminate-vu-verify.out @@ -0,0 +1,82 @@ +set babelfish_showplan_all on +GO + +SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS BIGINT) = 1) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS BIGINT) = 1) +Index Only Scan using cast_eliminate_pkey on cast_eliminate (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = 1) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS int) = 1) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS int) = 1) +Index Only Scan using cast_eliminate_pkey on cast_eliminate (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = 1) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate WHERE (ROID = cast(1 as bigint)) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate WHERE (ROID = cast(1 as bigint)) +Index Only Scan using cast_eliminate_pkey on cast_eliminate (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = '1'::bigint) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS BIGINT) = cast( 1 as bigint )) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS BIGINT) = cast( 1 as bigint )) +Index Only Scan using cast_eliminate_pkey on cast_eliminate (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = '1'::bigint) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate2 WHERE (CAST(ROID AS BIGINT) = 1) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate2 WHERE (CAST(ROID AS BIGINT) = 1) +Index Only Scan using cast_eliminate2_pkey on cast_eliminate2 (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = 1) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate2 WHERE (CAST(ROID AS int) = 1) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate2 WHERE (CAST(ROID AS int) = 1) +Seq Scan on cast_eliminate2 (cost=0.00..43.90 rows=11 width=4) + Filter: ((roid)::integer = 1) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate2 WHERE (ROID = cast(1 as bigint)) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate2 WHERE (ROID = cast(1 as bigint)) +Index Only Scan using cast_eliminate2_pkey on cast_eliminate2 (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = '1'::bigint) +~~END~~ + + +SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS BIGINT) = cast( 1 as bigint )) +GO +~~START~~ +text +Query Text: SELECT 1 AS [C1] FROM cast_eliminate WHERE (CAST(ROID AS BIGINT) = cast( 1 as bigint )) +Index Only Scan using cast_eliminate_pkey on cast_eliminate (cost=0.15..8.17 rows=1 width=4) + Index Cond: (roid = '1'::bigint) +~~END~~ + diff --git a/test/JDBC/expected/col_length-vu-cleanup.out b/test/JDBC/expected/col_length-vu-cleanup.out new file mode 100644 index 0000000000..d6a6590e21 --- /dev/null +++ b/test/JDBC/expected/col_length-vu-cleanup.out @@ -0,0 +1,97 @@ +USE babel_3489_test_db; +GO + +DROP TABLE IF EXISTS sys_column_length_test_table; +GO + +DROP TABLE IF EXISTS sys_col_length_test_schema.test_table; +GO + +DROP SCHEMA IF EXISTS sys_col_length_test_schema; +GO + +USE master; +GO + +DROP DATABASE IF EXISTS babel_3489_test_db; +GO + +-- Drop views +DROP VIEW IF EXISTS col_length_prepare_v1; +DROP VIEW IF EXISTS col_length_prepare_v2; +DROP VIEW IF EXISTS col_length_prepare_v3; +DROP VIEW IF EXISTS col_length_prepare_v4; +DROP VIEW IF EXISTS col_length_prepare_v5; +DROP VIEW IF EXISTS col_length_prepare_v6; +DROP VIEW IF EXISTS col_length_prepare_v7; +DROP VIEW IF EXISTS col_length_prepare_v8; +DROP VIEW IF EXISTS col_length_prepare_v9; +DROP VIEW IF EXISTS col_length_prepare_v10; +GO + +-- Drop procedures +DROP PROCEDURE IF EXISTS col_length_prepare_p1; +DROP PROCEDURE IF EXISTS col_length_prepare_p2; +DROP PROCEDURE IF EXISTS col_length_prepare_p3; +DROP PROCEDURE IF EXISTS col_length_prepare_p4; +DROP PROCEDURE IF EXISTS col_length_prepare_p5; +DROP PROCEDURE IF EXISTS col_length_prepare_p6; +DROP PROCEDURE IF EXISTS col_length_prepare_p7; +DROP PROCEDURE IF EXISTS col_length_prepare_p8; +DROP PROCEDURE IF EXISTS col_length_prepare_p9; +DROP PROCEDURE IF EXISTS col_length_prepare_p10; +GO + +-- Drop functions +DROP FUNCTION IF EXISTS col_length_prepare_f1(); +DROP FUNCTION IF EXISTS col_length_prepare_f2(); +DROP FUNCTION IF EXISTS col_length_prepare_f3(); +DROP FUNCTION IF EXISTS col_length_prepare_f4(); +DROP FUNCTION IF EXISTS col_length_prepare_f5(); +DROP FUNCTION IF EXISTS col_length_prepare_f6(); +DROP FUNCTION IF EXISTS col_length_prepare_f7(); +DROP FUNCTION IF EXISTS col_length_prepare_f8(); +DROP FUNCTION IF EXISTS col_length_prepare_f9(); +DROP FUNCTION IF EXISTS col_length_prepare_f10(); +DROP FUNCTION IF EXISTS col_length_prepare_f11(); +DROP FUNCTION IF EXISTS col_length_prepare_f12(); +DROP FUNCTION IF EXISTS col_length_prepare_f13(); +DROP FUNCTION IF EXISTS col_length_prepare_f14(); +DROP FUNCTION IF EXISTS col_length_prepare_f15(); +DROP FUNCTION IF EXISTS col_length_prepare_f16(); +GO + +-- Drop types +DROP TYPE IF EXISTS custom_char_10; +DROP TYPE IF EXISTS custom_varchar_20; +DROP TYPE IF EXISTS custom_binary_5; +DROP TYPE IF EXISTS custom_varbinary_15; +DROP TYPE IF EXISTS custom_nchar_8; +DROP TYPE IF EXISTS custom_nvarchar_16; +DROP TYPE IF EXISTS custom_text; +DROP TYPE IF EXISTS custom_image; +DROP TYPE IF EXISTS custom_ntext; +DROP TYPE IF EXISTS custom_sysname; +DROP TYPE IF EXISTS custom_sql_variant; +DROP TYPE IF EXISTS custom_xml; +DROP TYPE IF EXISTS custom_varcharmax; +DROP TYPE IF EXISTS custom_nvarcharmax; +DROP TYPE IF EXISTS custom_varbinarymax; +DROP TYPE IF EXISTS custom_bit; +DROP TYPE IF EXISTS custom_tinyint; +DROP TYPE IF EXISTS custom_bigint; +DROP TYPE IF EXISTS custom_smallint; +DROP TYPE IF EXISTS custom_smallmoney; +DROP TYPE IF EXISTS custom_money; +DROP TYPE IF EXISTS custom_smalldatetime; +DROP TYPE IF EXISTS custom_real; +DROP TYPE IF EXISTS custom_float; +DROP TYPE IF EXISTS custom_time; +DROP TYPE IF EXISTS custom_datetime; +DROP TYPE IF EXISTS custom_datetime2; +DROP TYPE IF EXISTS custom_datetimeoffset; +DROP TYPE IF EXISTS custom_uniqueidentifier; +DROP TYPE IF EXISTS custom_date; +DROP TYPE IF EXISTS custom_decimal_10_5; +DROP TYPE IF EXISTS custom_numeric_3_0; +GO diff --git a/test/JDBC/expected/col_length-vu-prepare.out b/test/JDBC/expected/col_length-vu-prepare.out new file mode 100644 index 0000000000..e2dcc42408 --- /dev/null +++ b/test/JDBC/expected/col_length-vu-prepare.out @@ -0,0 +1,365 @@ +CREATE DATABASE babel_3489_test_db; +GO + +USE babel_3489_test_db; +GO + +CREATE TABLE sys_column_length_test_table( + ID INT PRIMARY KEY, + col_char CHAR(10), + col_varchar VARCHAR(20), + col_binary BINARY(5), + col_varbinary VARBINARY(15), + col_nchar NCHAR(8), + col_nvarchar NVARCHAR(16), + col_text TEXT, + col_image IMAGE, + col_ntext NTEXT, + col_sysname sysname, + col_sql_variant SQL_VARIANT, + col_xml XML, + col_varcharmax VARCHAR(MAX), + col_nvarcharmax NVARCHAR(MAX), + col_varbinarymax VARBINARY(MAX), + col_bit BIT, + col_tinyint TINYINT, + col_bigint BIGINT, + col_smallint SMALLINT, + col_smallmoney SMALLMONEY, + col_money MONEY, + col_smalldatetime SMALLDATETIME, + col_real REAL, + col_float FLOAT, + col_time TIME, + col_datetime DATETIME, + col_datetime2 DATETIME2, + col_datetimeoffset DATETIMEOFFSET, + col_uniqueidentifier UNIQUEIDENTIFIER, + col_date DATE, + col_decimal DECIMAL(10,5), + col_numeric NUMERIC(3,0) +); +GO + +CREATE SCHEMA sys_col_length_test_schema; +GO + +CREATE TABLE sys_col_length_test_schema.test_table( + col_char CHAR(20), + col_varchar VARCHAR(30), + col_varbinary VARBINARY(40) +); +GO + +-- for user defined data types +-- Create User-Defined Types +CREATE TYPE custom_char_10 FROM CHAR(10); +GO + +CREATE TYPE custom_varchar_20 FROM VARCHAR(20); +GO + +CREATE TYPE custom_binary_5 FROM BINARY(5); +GO + +CREATE TYPE custom_varbinary_15 FROM VARBINARY(15); +GO + +CREATE TYPE custom_nchar_8 FROM NCHAR(8); +GO + +CREATE TYPE custom_nvarchar_16 FROM NVARCHAR(16); +GO + +CREATE TYPE custom_text FROM TEXT; +GO + +CREATE TYPE custom_image FROM IMAGE; +GO + +CREATE TYPE custom_ntext FROM NTEXT; +GO + +CREATE TYPE custom_sysname FROM sysname; +GO + +CREATE TYPE custom_sql_variant FROM SQL_VARIANT; +GO + +CREATE TYPE custom_xml FROM XML; +GO + +CREATE TYPE custom_varcharmax FROM VARCHAR(MAX); +GO + +CREATE TYPE custom_nvarcharmax FROM NVARCHAR(MAX); +GO + +CREATE TYPE custom_varbinarymax FROM VARBINARY(MAX); +GO + +CREATE TYPE custom_bit FROM BIT; +GO + +CREATE TYPE custom_tinyint FROM TINYINT; +GO + +CREATE TYPE custom_bigint FROM BIGINT; +GO + +CREATE TYPE custom_smallint FROM SMALLINT; +GO + +CREATE TYPE custom_smallmoney FROM SMALLMONEY; +GO + +CREATE TYPE custom_money FROM MONEY; +GO + +CREATE TYPE custom_smalldatetime FROM SMALLDATETIME; +GO + +CREATE TYPE custom_real FROM REAL; +GO + +CREATE TYPE custom_float FROM FLOAT; +GO + +CREATE TYPE custom_time FROM TIME; +GO + +CREATE TYPE custom_datetime FROM DATETIME; +GO + +CREATE TYPE custom_datetime2 FROM DATETIME2; +GO + +CREATE TYPE custom_datetimeoffset FROM DATETIMEOFFSET; +GO + +CREATE TYPE custom_uniqueidentifier FROM UNIQUEIDENTIFIER; +GO + +CREATE TYPE custom_date FROM DATE; +GO + +CREATE TYPE custom_decimal_10_5 FROM DECIMAL(10,5); +GO + +CREATE TYPE custom_numeric_3_0 FROM NUMERIC(3,0); +GO + +-- Create Table with User-Defined Data Types +CREATE TABLE udd_test_table ( + col_customchar custom_char_10, + col_customvarchar custom_varchar_20, + col_custombinary custom_binary_5, + col_customvarbinary custom_varbinary_15, + col_customnchar custom_nchar_8, + col_customnvarchar custom_nvarchar_16, + col_customtext custom_text, + col_customimage custom_image, + col_customntext custom_ntext, + col_customsysname custom_sysname, + col_customsqlvariant custom_sql_variant, + col_customxml custom_xml, + col_customvarcharmax custom_varcharmax, + col_customnvarcharmax custom_nvarcharmax, + col_customvarbinarymax custom_varbinarymax, + col_custombit custom_bit, + col_customtinyint custom_tinyint, + col_custombigint custom_bigint, + col_customsmallint custom_smallint, + col_customsmallmoney custom_smallmoney, + col_custommoney custom_money, + col_customsmalldatetime custom_smalldatetime, + col_customreal custom_real, + col_customfloat custom_float, + col_customtime custom_time, + col_customdatetime custom_datetime, + col_customdatetime2 custom_datetime2, + col_customdatetimeoffset custom_datetimeoffset, + col_customuniqueidentifier custom_uniqueidentifier, + col_customdate custom_date, + col_customdecimal custom_decimal_10_5, + col_customnumeric custom_numeric_3_0 +); +GO + +CREATE VIEW col_length_prepare_v1 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'ID')); +GO + +CREATE VIEW col_length_prepare_v2 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_char')); +GO + +CREATE VIEW col_length_prepare_v3 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_varchar')); +GO + +CREATE VIEW col_length_prepare_v4 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_binary')); +GO + +CREATE VIEW col_length_prepare_v5 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_varbinary')); +GO + +CREATE VIEW col_length_prepare_v6 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_nchar')); +GO + +CREATE VIEW col_length_prepare_v7 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_float')); +GO + +CREATE VIEW col_length_prepare_v8 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_time')); +GO + +CREATE VIEW col_length_prepare_v9 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_datetime')); +GO + +CREATE VIEW col_length_prepare_v10 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_datetime2')); +GO + +CREATE PROCEDURE col_length_prepare_p1 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_nvarchar')); +GO + +CREATE PROCEDURE col_length_prepare_p2 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_text')); +GO + +CREATE PROCEDURE col_length_prepare_p3 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_image')); +GO + +CREATE PROCEDURE col_length_prepare_p4 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_ntext')); +GO + +CREATE PROCEDURE col_length_prepare_p5 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_sysname')); +GO + +CREATE PROCEDURE col_length_prepare_p6 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_sql_variant')); +GO + +CREATE PROCEDURE col_length_prepare_p7 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_datetimeoffset')); +GO + +CREATE PROCEDURE col_length_prepare_p8 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'col_uniqueidentifier')); +GO + +-- Invalid column, should return NULL +CREATE PROCEDURE col_length_prepare_p9 AS (SELECT COL_LENGTH('sys_column_length_test_table', 'test_col')); +GO + +-- Invalid table, should return NULL +CREATE PROCEDURE col_length_prepare_p10 AS (SELECT COL_LENGTH('sys_column_length_test_table_invalid', 'col_char')); +GO + +CREATE FUNCTION col_length_prepare_f1() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_xml')); +END +GO + +CREATE FUNCTION col_length_prepare_f2() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_varcharmax')); +END +GO + +CREATE FUNCTION col_length_prepare_f3() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_nvarcharmax')); +END +GO + +CREATE FUNCTION col_length_prepare_f4() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_varbinarymax')); +END +GO + +CREATE FUNCTION col_length_prepare_f5() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_bit')); +END +GO + +CREATE FUNCTION col_length_prepare_f6() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_tinyint')); +END +GO + +CREATE FUNCTION col_length_prepare_f7() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_bigint')); +END +GO + +CREATE FUNCTION col_length_prepare_f8() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_smallint')); +END +GO + +CREATE FUNCTION col_length_prepare_f9() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_smallmoney')); +END +GO + +CREATE FUNCTION col_length_prepare_f10() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_money')); +END +GO + +CREATE FUNCTION col_length_prepare_f11() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_smalldatetime')); +END +GO + +CREATE FUNCTION col_length_prepare_f12() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 'col_real')); +END +GO + +-- Invalid column, should return NULL +CREATE FUNCTION col_length_prepare_f13() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', 1)); +END +GO + +-- Invalid column, should return NULL +CREATE FUNCTION col_length_prepare_f14() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', -1)); +END +GO + +-- Invalid table, should return NULL +CREATE FUNCTION col_length_prepare_f15() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH(NULL, 'col_char')); +END +GO + +-- NULL column, should return NULL +CREATE FUNCTION col_length_prepare_f16() +RETURNS SMALLINT AS +BEGIN +RETURN (SELECT COL_LENGTH('sys_column_length_test_table', NULL)); +END +GO diff --git a/test/JDBC/expected/col_length-vu-verify.out b/test/JDBC/expected/col_length-vu-verify.out new file mode 100644 index 0000000000..a5cae67a16 --- /dev/null +++ b/test/JDBC/expected/col_length-vu-verify.out @@ -0,0 +1,711 @@ +USE babel_3489_test_db; +GO + +SELECT * FROM col_length_prepare_v1 +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT * FROM col_length_prepare_v2 +GO +~~START~~ +smallint +10 +~~END~~ + + +SELECT * FROM col_length_prepare_v3 +GO +~~START~~ +smallint +20 +~~END~~ + + +SELECT * FROM col_length_prepare_v4 +GO +~~START~~ +smallint +5 +~~END~~ + + +SELECT * FROM col_length_prepare_v5 +GO +~~START~~ +smallint +15 +~~END~~ + + +SELECT * FROM col_length_prepare_v6 +GO +~~START~~ +smallint +16 +~~END~~ + + +SELECT * FROM col_length_prepare_v7 +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM col_length_prepare_v8 +GO +~~START~~ +smallint +5 +~~END~~ + + +SELECT * FROM col_length_prepare_v9 +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM col_length_prepare_v10 +GO +~~START~~ +smallint +8 +~~END~~ + + +EXEC col_length_prepare_p1 +GO +~~START~~ +smallint +32 +~~END~~ + + +EXEC col_length_prepare_p2 +GO +~~START~~ +smallint +16 +~~END~~ + + +EXEC col_length_prepare_p3 +GO +~~START~~ +smallint +16 +~~END~~ + + +EXEC col_length_prepare_p4 +GO +~~START~~ +smallint +16 +~~END~~ + + +EXEC col_length_prepare_p5 +GO +~~START~~ +smallint +256 +~~END~~ + + +EXEC col_length_prepare_p6 +GO +~~START~~ +smallint +8016 +~~END~~ + + +EXEC col_length_prepare_p7 +GO +~~START~~ +smallint +10 +~~END~~ + + +EXEC col_length_prepare_p8 +GO +~~START~~ +smallint +16 +~~END~~ + + +EXEC col_length_prepare_p9 +GO +~~START~~ +smallint + +~~END~~ + + +EXEC col_length_prepare_p10 +GO +~~START~~ +smallint + +~~END~~ + + +SELECT col_length_prepare_f1() +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT col_length_prepare_f2() +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT col_length_prepare_f3() +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT col_length_prepare_f4() +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT col_length_prepare_f5() +GO +~~START~~ +smallint +1 +~~END~~ + + +SELECT col_length_prepare_f6() +GO +~~START~~ +smallint +1 +~~END~~ + + +SELECT col_length_prepare_f7() +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT col_length_prepare_f8() +GO +~~START~~ +smallint +2 +~~END~~ + + +SELECT col_length_prepare_f9() +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT col_length_prepare_f10() +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT col_length_prepare_f11() +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT col_length_prepare_f12() +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT col_length_prepare_f13() +GO +~~START~~ +smallint + +~~END~~ + + +SELECT col_length_prepare_f14() +GO +~~START~~ +smallint + +~~END~~ + + +SELECT col_length_prepare_f15() +GO +~~START~~ +smallint + +~~END~~ + + +SELECT col_length_prepare_f16() +GO +~~START~~ +smallint + +~~END~~ + + +SELECT * FROM sys.COL_LENGTH(NULL, NULL); +GO +~~START~~ +smallint + +~~END~~ + + +SELECT * FROM sys.COL_LENGTH(); +GO +~~ERROR (Code: 201)~~ + +~~ERROR (Message: function sys.col_length expects parameter "object_name", which was not supplied.)~~ + + +SELECT * FROM sys.COL_LENGTH('sys_col_length_test_schema.test_table', 'col_char'); +GO +~~START~~ +smallint +20 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_col_length_test_schema.test_table', 'col_varchar'); +GO +~~START~~ +smallint +30 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_col_length_test_schema.test_table', 'col_varbinary'); +GO +~~START~~ +smallint +40 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_col_length_test_schema.invalid_test_table', 'col_char'); +GO +~~START~~ +smallint + +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_column_length_test_table', 'col_date'); +GO +~~START~~ +smallint +3 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_column_length_test_table', 'col_decimal'); +GO +~~START~~ +smallint +9 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_column_length_test_table', 'col_numeric'); +GO +~~START~~ +smallint +5 +~~END~~ + + +-- case sensitive check +SELECT * FROM sys.COL_LENGTH('sys_column_length_test_TABLE', 'COL_NUMERIC'); +GO +~~START~~ +smallint +5 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('', ''); +GO +~~START~~ +smallint + +~~END~~ + + +-- arguments with CAST +SELECT * FROM sys.COL_LENGTH('sys_column_length_test_TABLE', CAST('col_numeric' as VARCHAR(20))); +GO +~~START~~ +smallint +5 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('sys_column_length_test_table', (SELECT CAST('123' as text))); +GO +~~START~~ +smallint + +~~END~~ + + +SELECT * FROM sys.COL_LENGTH((SELECT CAST('abc#$' as VARCHAR(10))), 'col_numeric'); +GO +~~START~~ +smallint + +~~END~~ + + +-- Using COL_LENGTH() in queries on tables, returning columns with even length +WITH ColumnLengths AS ( + SELECT COLUMN_NAME, + sys.COL_LENGTH(TABLE_NAME, COLUMN_NAME) AS ColumnLength + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME = 'sys_column_length_test_table' +) +SELECT COLUMN_NAME, ColumnLength +FROM ColumnLengths +WHERE ColumnLength % 2 = 0; +GO +~~START~~ +nvarchar#!#smallint +id#!#4 +col_char#!#10 +col_varchar#!#20 +col_nchar#!#16 +col_nvarchar#!#32 +col_text#!#16 +col_image#!#16 +col_ntext#!#16 +col_sysname#!#256 +col_sql_variant#!#8016 +col_bigint#!#8 +col_smallint#!#2 +col_smallmoney#!#4 +col_money#!#8 +col_smalldatetime#!#4 +col_real#!#4 +col_float#!#8 +col_datetime#!#8 +col_datetime2#!#8 +col_datetimeoffset#!#10 +col_uniqueidentifier#!#16 +~~END~~ + + +-- Using COL_LENGTH() in expressions +SELECT + CASE + WHEN sys.COL_LENGTH('sys_column_length_test_table', 'col_sql_variant') > 8015 + THEN 'SQL Variant Column' + ELSE 'Other Column' + END AS ColumnStatus; +GO +~~START~~ +text +SQL Variant Column +~~END~~ + + +-- Test Cases for User-Defined Data Types +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customchar'); +GO +~~START~~ +smallint +10 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customvarchar'); +GO +~~START~~ +smallint +20 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_custombinary'); +GO +~~START~~ +smallint +5 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customvarbinary'); +GO +~~START~~ +smallint +15 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customnchar'); +GO +~~START~~ +smallint +16 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customnvarchar'); +GO +~~START~~ +smallint +32 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customtext'); +GO +~~START~~ +smallint +16 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customimage'); +GO +~~START~~ +smallint +16 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customntext'); +GO +~~START~~ +smallint +16 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customsysname'); +GO +~~START~~ +smallint +256 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customsqlvariant'); +GO +~~START~~ +smallint +8016 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customxml'); +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customvarcharmax'); +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customnvarcharmax'); +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customvarbinarymax'); +GO +~~START~~ +smallint +-1 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_custombit'); +GO +~~START~~ +smallint +1 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customtinyint'); +GO +~~START~~ +smallint +1 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_custombigint'); +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customsmallint'); +GO +~~START~~ +smallint +2 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customsmallmoney'); +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_custommoney'); +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customsmalldatetime'); +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customreal'); +GO +~~START~~ +smallint +4 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customfloat'); +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customtime'); +GO +~~START~~ +smallint +5 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customdatetime'); +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customdatetime2'); +GO +~~START~~ +smallint +8 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customdatetimeoffset'); +GO +~~START~~ +smallint +10 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customuniqueidentifier'); +GO +~~START~~ +smallint +16 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customdate'); +GO +~~START~~ +smallint +3 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customdecimal'); +GO +~~START~~ +smallint +9 +~~END~~ + + +SELECT * FROM sys.COL_LENGTH('udd_test_table', 'col_customnumeric'); +GO +~~START~~ +smallint +5 +~~END~~ + diff --git a/test/JDBC/expected/constraint_column_usage.out b/test/JDBC/expected/constraint_column_usage.out index 8ec12f1cbb..416044b370 100644 --- a/test/JDBC/expected/constraint_column_usage.out +++ b/test/JDBC/expected/constraint_column_usage.out @@ -52,7 +52,7 @@ nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar ~~END~~ -create table constraint_column_usage_tbl6 (arg12 int, arg13 int, UNIQUE(arg13)); +create table constraint_column_usage_tbl6 (arg12 int, arg13 int not null, UNIQUE(arg13)); go SELECT * FROM information_schema.CONSTRAINT_COLUMN_USAGE WHERE TABLE_NAME NOT LIKE 'sys%' ORDER BY COLUMN_NAME; 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/database_1__preparation__BABEL-4516-vu-prepare.out b/test/JDBC/expected/database_1__preparation__BABEL-4516-vu-prepare.out new file mode 100644 index 0000000000..d2ecdf8a78 --- /dev/null +++ b/test/JDBC/expected/database_1__preparation__BABEL-4516-vu-prepare.out @@ -0,0 +1,79 @@ +USE master; +GO + +-- CREATE a user defined database +CREATE DATABASE [DATABASE_1]; +GO + +-- Populate the database +-- Schemas +USE [DATABASE_1]; +GO + +CREATE SCHEMA [DB1_Schema_1]; +GO + +CREATE SCHEMA [db1_SCHEMA_2]; +GO + +CREATE SCHEMA [DB1_My_Schema]; +GO + +-- Create few logins and users +CREATE LOGIN [DB1_Login_1] WITH PASSWORD = '12345678'; +GO + +CREATE USER [DB1_User_1] FOR LOGIN [DB1_Login_1]; +GO + +CREATE LOGIN [DB1_Login_2] WITH PASSWORD = 'abc'; +GO + +CREATE LOGIN [DB1_User_3] WITH PASSWORD = 'abc'; +GO + +CREATE USER [DB1_User_3] WITH DEFAULT_SCHEMA = [DB1_Schema_1]; +GO + +-- Tables +USE [DATABASE_1]; +GO + +CREATE TABLE [Table_1] ([Col_1] INT NOT NULL, [COL 2] INT NOT NULL, PRIMARY KEY ([Col_1], [COL 2])); +GO + +INSERT INTO [Table_1] SELECT x, x + 1 FROM generate_series(1, 1000) x; +GO +~~ROW COUNT: 1000~~ + + +CREATE TABLE [DB1_My_Schema].[Table_2] ([Col_1] INT NOT NULL, [COL 2] INT NOT NULL, FOREIGN KEY ([Col_1], [COL 2]) REFERENCES [Table_1]([Col_1], [COL 2])); +GO + +INSERT INTO [DB1_My_Schema].[Table_2] SELECT x, x + 1 FROM generate_series(1, 1000) x; +GO +~~ROW COUNT: 1000~~ + + +-- Views +CREATE view [db1_SCHEMA_2].[DB1 My View] AS SELECT * FROM [Table_1]; +GO + +-- Procedures +CREATE PROC [db1_SCHEMA_2].[babel_user_ext] AS +BEGIN + SELECT rolname, login_name, type, orig_username, database_name + FROM sys.babelfish_authid_user_ext + WHERE orig_username LIKE 'DB1_User_%' + ORDER BY rolname, orig_username +END +GO + +-- Functions +CREATE FUNCTION [db1_SCHEMA_2].[Func_2] (@a INT) +RETURNS @tab table(a INT, b INT) AS +BEGIN + INSERT INTO @tab SELECT * FROM [DB1_My_Schema].[Table_2] WHERE Col_1 = @a; + RETURN; +END; +GO diff --git a/test/JDBC/expected/database_1__verification_cleanup__BABEL-4516-vu-cleanup.out b/test/JDBC/expected/database_1__verification_cleanup__BABEL-4516-vu-cleanup.out new file mode 100644 index 0000000000..04c84782a0 --- /dev/null +++ b/test/JDBC/expected/database_1__verification_cleanup__BABEL-4516-vu-cleanup.out @@ -0,0 +1,34 @@ +-- Verify that we are able to drop all the database objects including +-- the database itself. +USE [DATABASE_1]; +GO + +DROP VIEW [db1_SCHEMA_2].[DB1 My View]; +GO + +DROP FUNCTION [db1_SCHEMA_2].[Func_2]; +GO + +DROP PROCEDURE [db1_SCHEMA_2].[babel_user_ext]; +GO + +DROP TABLE [DB1_My_Schema].[Table_2]; +GO + +DROP TABLE [Table_1]; +GO + +DROP SCHEMA [DB1_Schema_1]; +GO + +DROP SCHEMA [db1_SCHEMA_2]; +GO + +DROP SCHEMA [DB1_My_Schema]; +GO + +USE master; +GO + +DROP DATABASE [DATABASE_1]; +GO diff --git a/test/JDBC/expected/database_1__verification_cleanup__BABEL-4516-vu-verify.out b/test/JDBC/expected/database_1__verification_cleanup__BABEL-4516-vu-verify.out new file mode 100644 index 0000000000..87db041e87 --- /dev/null +++ b/test/JDBC/expected/database_1__verification_cleanup__BABEL-4516-vu-verify.out @@ -0,0 +1,59 @@ +USE [DATABASE_1]; +GO + +-- login_name should be empty and database users should +-- be present after database-level restore. +EXEC [db1_SCHEMA_2].[babel_user_ext]; +GO +~~START~~ +varchar#!#varchar#!#char#!#nvarchar#!#nvarchar +database_1_db1_user_1#!##!#S#!#DB1_User_1#!#database_1 +database_1_db1_user_3#!##!#S#!#DB1_User_3#!#database_1 +~~END~~ + + +-- dbo and guest roles should be member of sysadmin +SELECT r.rolname FROM pg_catalog.pg_auth_members m + JOIN pg_catalog.pg_roles r + ON (m.roleid = r.oid) +WHERE m.member = (SELECT oid FROM pg_roles WHERE rolname = 'sysadmin') +AND r.rolname LIKE 'database_1%' ORDER BY r.rolname; +GO +~~START~~ +varchar +database_1_dbo +database_1_guest +~~END~~ + + +SELECT COUNT(*) FROM [Table_1]; +GO +~~START~~ +int +1000 +~~END~~ + + +SELECT COUNT(*) FROM [DB1_My_Schema].[Table_2]; +GO +~~START~~ +int +1000 +~~END~~ + + +SELECT COUNT(*) FROM [db1_SCHEMA_2].[DB1 My View]; +GO +~~START~~ +int +1000 +~~END~~ + + +SELECT * FROM [db1_SCHEMA_2].[Func_2](555); +GO +~~START~~ +int#!#int +555#!#556 +~~END~~ + diff --git a/test/JDBC/expected/dateadd-vu-cleanup.out b/test/JDBC/expected/dateadd-vu-cleanup.out new file mode 100644 index 0000000000..5e7690b0cb --- /dev/null +++ b/test/JDBC/expected/dateadd-vu-cleanup.out @@ -0,0 +1,29 @@ +DROP PROCEDURE dateadd_p1 +GO + +DROP PROCEDURE dateadd_p2 +GO + +DROP PROCEDURE dateadd_p3 +GO + +DROP PROCEDURE dateadd_p4 +GO + +DROP PROCEDURE dateadd_p5 +GO + +DROP PROCEDURE dateadd_p6 +GO + +DROP PROCEDURE dateadd_p7 +GO + +DROP PROCEDURE dateadd_p8 +GO + +DROP PROCEDURE dateadd_p9 +GO + +DROP PROCEDURE dateadd_p10 +GO diff --git a/test/JDBC/expected/dateadd-vu-prepare.out b/test/JDBC/expected/dateadd-vu-prepare.out new file mode 100644 index 0000000000..eb893e92e0 --- /dev/null +++ b/test/JDBC/expected/dateadd-vu-prepare.out @@ -0,0 +1,29 @@ +CREATE PROCEDURE dateadd_p1 as (select dateadd(day, 2, cast('1900-01-01' as date))); +GO + +CREATE PROCEDURE dateadd_p2 as (select dateadd(hour, 2, cast('01:01:21' as time))); +GO + +CREATE PROCEDURE dateadd_p3 as (select dateadd(hour, 5, cast('01:01:21 +10:00' as datetimeoffset))); +GO + +CREATE PROCEDURE dateadd_p4 as (select dateadd(second, 1, cast('1999-12-31 23:59:59' as datetime))); +GO + +CREATE PROCEDURE dateadd_p5 as (select dateadd(millisecond, 1, cast('1999-12-31 23:59:59' as datetime))); +GO + +CREATE PROCEDURE dateadd_p6 as (select dateadd(millisecond, 1, cast('1999-12-31 23:59:59' as datetime2))); +GO + +CREATE PROCEDURE dateadd_p7 as (select dateadd(day, 2, cast('01:01:21' as time))); +GO + +CREATE PROCEDURE dateadd_p8 as (select dateadd(hour, 2, cast('1900-01-01' as date))); +GO + +CREATE PROCEDURE dateadd_p9 as (select dateadd(minute, -70, cast('2016-12-26 00:30:05.523456+8' as datetimeoffset))); +GO + +CREATE PROCEDURE dateadd_p10 as (select sys.dateadd_internal_datetime('day', 1, cast('2016-12-26 00:30:05' as datetime), 3)); +GO diff --git a/test/JDBC/expected/dateadd-vu-verify.out b/test/JDBC/expected/dateadd-vu-verify.out new file mode 100644 index 0000000000..b74a4cf799 --- /dev/null +++ b/test/JDBC/expected/dateadd-vu-verify.out @@ -0,0 +1,185 @@ +exec dateadd_p1 +GO +~~START~~ +date +1900-01-03 +~~END~~ + + +exec dateadd_p2 +GO +~~START~~ +time +03:01:21.0000000 +~~END~~ + + +exec dateadd_p3 +GO +~~START~~ +datetimeoffset +1900-01-01 06:01:21.0000000 +10:00 +~~END~~ + + +exec dateadd_p4 +GO +~~START~~ +datetime +2000-01-01 00:00:00.0 +~~END~~ + + +exec dateadd_p5 +GO +~~START~~ +datetime +1999-12-31 23:59:59.0 +~~END~~ + + +exec dateadd_p6 +GO +~~START~~ +datetime2 +1999-12-31 23:59:59.0010000 +~~END~~ + + +exec dateadd_p7 +GO +~~ERROR (Code: 9810)~~ + +~~ERROR (Message: The datepart day is not supported by date function dateadd for data type time.)~~ + + +exec dateadd_p8 +GO +~~ERROR (Code: 9810)~~ + +~~ERROR (Message: The datepart hour is not supported by date function dateadd for data type date.)~~ + + +exec dateadd_p9 +GO +~~START~~ +datetimeoffset +2016-12-25 23:20:05.5234560 +08:00 +~~END~~ + + +exec dateadd_p10 +GO +~~START~~ +datetime +2016-12-27 00:30:05.0 +~~END~~ + + +begin transaction +go + +SELECT dateadd(fakeoption, 2, cast('1900-01-01' as date)); +go +~~ERROR (Code: 155)~~ + +~~ERROR (Message: 'fakeoption' is not a recognized dateadd option)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT dateadd(day, 2, cast('01:01:21' as time)); +go +~~ERROR (Code: 9810)~~ + +~~ERROR (Message: The datepart day is not supported by date function dateadd for data type time.)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT DATEADD(YY,-300,getdate()); +go +~~START~~ +datetime +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT DATEADD(YY,-30000000, cast('1900-01-01' as datetime)); +go +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT DATEADD(year,-300000000,cast('1900-01-01' as datetime)); +go +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + 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/expected/datediff-vu-cleanup.out b/test/JDBC/expected/datediff-vu-cleanup.out new file mode 100644 index 0000000000..64b76e5988 --- /dev/null +++ b/test/JDBC/expected/datediff-vu-cleanup.out @@ -0,0 +1,47 @@ +DROP PROCEDURE datediff_p1 +GO + +DROP PROCEDURE datediff_p2 +GO + +DROP PROCEDURE datediff_p3 +GO + +DROP PROCEDURE datediff_p4 +GO + +DROP PROCEDURE datediff_p5 +GO + +DROP PROCEDURE datediff_p6 +GO + +DROP PROCEDURE datediff_p7 +GO + +DROP PROCEDURE datediff_p8 +GO + +DROP PROCEDURE datediff_p9 +GO + +DROP PROCEDURE datediff_p10 +GO + +DROP PROCEDURE datediff_p11 +GO + +DROP PROCEDURE datediff_p12 +GO + +DROP PROCEDURE datediff_p13 +GO + +DROP PROCEDURE datediff_p14 +GO + +DROP PROCEDURE datediff_p15 +GO + +DROP PROCEDURE datediff_p16 +GO diff --git a/test/JDBC/expected/datediff-vu-prepare.out b/test/JDBC/expected/datediff-vu-prepare.out new file mode 100644 index 0000000000..bad18b9072 --- /dev/null +++ b/test/JDBC/expected/datediff-vu-prepare.out @@ -0,0 +1,60 @@ +-- 123 +CREATE PROCEDURE datediff_p1 as (select datediff(year, cast('1900-01-01' as datetime), cast('2023-01-02' as datetime))); +GO + +-- -30 +CREATE PROCEDURE datediff_p2 as (select datediff(year, cast('2020-01-01' as datetime), cast('1990-01-02' as datetime))); +GO + +-- -120 +CREATE PROCEDURE datediff_p3 as (select datediff(quarter, cast('2020-01-01' as datetime), cast('1990-01-02' as datetime))); +GO + +-- 24 +CREATE PROCEDURE datediff_p4 as (select datediff(month, cast('2020-01-01' as datetime), cast('2022-01-02' as datetime))); +GO + +-- 105 +CREATE PROCEDURE datediff_p5 as (select datediff(week, cast('2020-01-01' as datetime2), cast('2022-01-02' as datetime2))); +GO + +-- -10957 +CREATE PROCEDURE datediff_p6 as (select datediff(day, cast('2020-01-01' as smalldatetime), cast('1990-01-01' as smalldatetime))); +GO + +-- -262963 +CREATE PROCEDURE datediff_p7 as (select datediff(hour, cast('2020-01-01 01:01:20.99' as smalldatetime), cast('1990-01-01 06:01:20.99' as smalldatetime))); +GO +-- -15777780 +CREATE PROCEDURE datediff_p8 as (select datediff(minute, cast('2020-01-01 01:01:20.99' as datetime), cast('1990-01-01 06:01:20.99' as smalldatetime))); +GO + +-- 157885200 +CREATE PROCEDURE datediff_p9 as (select datediff(second, cast('2000-01-01 01:01:20.99' as datetime), cast('2005-01-01 10:01:20.99' as datetime))); +GO + +-- 32400000 +CREATE PROCEDURE datediff_p10 as (select datediff(millisecond, cast('2005-01-01 01:01:20.99' as datetime), cast('2005-01-01 10:01:20.99' as datetime))); +GO + +-- 1200000000 +CREATE PROCEDURE datediff_p11 as (select datediff(microsecond, cast('2005-01-01 01:01:20.99' as datetime), cast('2005-01-01 1:21:20.99' as datetime))); +GO + +-- overflow +CREATE PROCEDURE datediff_p12 as (select datediff(nanosecond, cast('2005-01-01 01:01:20.99' as datetime), cast('2005-01-01 1:21:20.99' as datetime))); +GO + +-- 1200000000000 +CREATE PROCEDURE datediff_p13 as (select datediff_big(nanosecond, cast('2005-01-01 01:01:20.99' as datetime), cast('2005-01-01 1:21:20.99' as datetime))); +GO + +-- 15 +CREATE PROCEDURE datediff_p14 as (select datediff(hour, cast('2020-01-01 01:01:20.99 +10:00' as datetimeoffset), cast('2020-01-01 06:01:20.99' as datetimeoffset))); +GO + +CREATE PROCEDURE datediff_p15 as (select datediff(dayofyear, cast('2020-01-01 01:01:20.99 +10:00' as datetimeoffset), cast('2023-01-01 06:01:20.99' as datetimeoffset))); +GO + +CREATE PROCEDURE datediff_p16 as (select sys.datediff_internal_big('week', cast('2005-01-01 01:01:20.99' as datetime), cast('2005-01-01 01:01:20.99' as datetime))); +GO diff --git a/test/JDBC/expected/datediff-vu-verify.out b/test/JDBC/expected/datediff-vu-verify.out new file mode 100644 index 0000000000..1ea3659990 --- /dev/null +++ b/test/JDBC/expected/datediff-vu-verify.out @@ -0,0 +1,182 @@ +-- 123 +exec datediff_p1 +GO +~~START~~ +int +123 +~~END~~ + + +-- -30 +exec datediff_p2 +GO +~~START~~ +int +-30 +~~END~~ + + +-- -120 +exec datediff_p3 +GO +~~START~~ +int +-120 +~~END~~ + + +-- 24 +exec datediff_p4 +GO +~~START~~ +int +24 +~~END~~ + + +-- 105 +exec datediff_p5 +GO +~~START~~ +int +105 +~~END~~ + + +-- -10957 +exec datediff_p6 +GO +~~START~~ +int +-10957 +~~END~~ + + +-- -262963 +exec datediff_p7 +GO +~~START~~ +int +-262963 +~~END~~ + + +-- -15777780 +exec datediff_p8 +GO +~~START~~ +int +-15777780 +~~END~~ + + +-- 157885200 +exec datediff_p9 +GO +~~START~~ +int +157885200 +~~END~~ + + +-- 32400000 +exec datediff_p10 +GO +~~START~~ +int +32400000 +~~END~~ + + +-- 1200000000 +exec datediff_p11 +GO +~~START~~ +int +1200000000 +~~END~~ + + +-- overflow +exec datediff_p12 +GO +~~ERROR (Code: 535)~~ + +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ + + +-- 1200000000000 +exec datediff_p13 +GO +~~START~~ +bigint +1200000000000 +~~END~~ + + +-- 15 +exec datediff_p14 +GO +~~START~~ +int +15 +~~END~~ + + +exec datediff_p15 +GO +~~START~~ +int +1097 +~~END~~ + + +exec datediff_p16 +GO +~~START~~ +bigint +0 +~~END~~ + + +begin transaction +go + +SELECT DATEDIFF(fakeoption, cast('2023-01-01 01:01:20.98' as datetime), cast('2023-01-01 01:01:20.98' as datetime)) +go +~~ERROR (Code: 155)~~ + +~~ERROR (Message: 'fakeoption' is not a recognized datediff option)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT DATEDIFF(nanosecond, cast('1900-01-01 01:01:20.98' as datetime), cast('2023-01-01 01:01:20.98' as datetime)) +go +~~ERROR (Code: 535)~~ + +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO diff --git a/test/JDBC/expected/datediff_big-vu-verify.out b/test/JDBC/expected/datediff_big-vu-verify.out index cba97675d7..310c4dad30 100644 --- a/test/JDBC/expected/datediff_big-vu-verify.out +++ b/test/JDBC/expected/datediff_big-vu-verify.out @@ -2,22 +2,22 @@ SELECT * FROM datediff_big_vu_prepare_v1 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -1000#!#4000#!#12000#!#365243#!#365243#!#52177#!#8765832#!#525949920#!#31556995200#!#31556995200000#!#31556995200000000#!#6311433600000000000 +1000#!#4000#!#12000#!#365243#!#365243#!#52178#!#8765832#!#525949920#!#31556995200#!#31556995200000#!#31556995200000000#!#6311433600000000000 ~~END~~ SELECT * FROM datediff_big_vu_prepare_v2 GO -~~ERROR (Code: 8115)~~ +~~ERROR (Code: 535)~~ -~~ERROR (Message: bigint out of range)~~ +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ SELECT * FROM datediff_big_vu_prepare_v3 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -200#!#803#!#2411#!#73413#!#73413#!#10487#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 +200#!#803#!#2411#!#73413#!#73413#!#10488#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 ~~END~~ @@ -25,7 +25,7 @@ SELECT * FROM datediff_big_vu_prepare_v4 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -200#!#803#!#2411#!#73413#!#73413#!#10487#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 +200#!#803#!#2411#!#73413#!#73413#!#10488#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 ~~END~~ @@ -33,7 +33,7 @@ SELECT * FROM datediff_big_vu_prepare_v5 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -100#!#396#!#1189#!#36160#!#36160#!#5165#!#867840#!#52070401#!#3124224060#!#3124224060000#!#3124224060000000#!#3124224060000000000 +100#!#396#!#1189#!#36160#!#36160#!#5166#!#867840#!#52070401#!#3124224060#!#3124224060000#!#3124224060000000#!#3124224060000000000 ~~END~~ @@ -55,16 +55,18 @@ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#! SELECT * FROM datediff_big_vu_prepare_v8 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: unit "year" not supported for type time without time zone)~~ +~~START~~ +bigint +0 +~~END~~ SELECT * FROM datediff_big_vu_prepare_v9 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: operator is not unique: time without time zone sys.- time without time zone)~~ +~~START~~ +bigint +51 +~~END~~ SELECT * FROM datediff_big_vu_prepare_v10 @@ -95,22 +97,22 @@ EXEC datediff_big_vu_prepare_p1 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -1000#!#4000#!#12000#!#365243#!#365243#!#52177#!#8765832#!#525949920#!#31556995200#!#31556995200000#!#31556995200000000#!#6311433600000000000 +1000#!#4000#!#12000#!#365243#!#365243#!#52178#!#8765832#!#525949920#!#31556995200#!#31556995200000#!#31556995200000000#!#6311433600000000000 ~~END~~ EXEC datediff_big_vu_prepare_p2 GO -~~ERROR (Code: 8115)~~ +~~ERROR (Code: 535)~~ -~~ERROR (Message: bigint out of range)~~ +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ EXEC datediff_big_vu_prepare_p3 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -200#!#803#!#2411#!#73413#!#73413#!#10487#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 +200#!#803#!#2411#!#73413#!#73413#!#10488#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 ~~END~~ @@ -118,7 +120,7 @@ EXEC datediff_big_vu_prepare_p4 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -200#!#803#!#2411#!#73413#!#73413#!#10487#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 +200#!#803#!#2411#!#73413#!#73413#!#10488#!#1761912#!#105714720#!#6342883200#!#6342883200000#!#6342883200000000#!#6342883200000000000 ~~END~~ @@ -126,7 +128,7 @@ EXEC datediff_big_vu_prepare_p5 GO ~~START~~ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint -100#!#396#!#1189#!#36160#!#36160#!#5165#!#867840#!#52070401#!#3124224060#!#3124224060000#!#3124224060000000#!#3124224060000000000 +100#!#396#!#1189#!#36160#!#36160#!#5166#!#867840#!#52070401#!#3124224060#!#3124224060000#!#3124224060000000#!#3124224060000000000 ~~END~~ @@ -148,16 +150,18 @@ bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#!#bigint#! EXEC datediff_big_vu_prepare_p8 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: unit "year" not supported for type time without time zone)~~ +~~START~~ +bigint +0 +~~END~~ EXEC datediff_big_vu_prepare_p9 GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: unit "year" not supported for type time without time zone)~~ +~~START~~ +bigint +0 +~~END~~ EXEC datediff_big_vu_prepare_p10 @@ -190,3 +194,66 @@ bigint#!#bigint#!#bigint#!#bigint 0#!#366#!#739013#!#3652424 ~~END~~ + +begin transaction +go + +SELECT DATEDIFF_BIG(fakeoption, cast('2023-01-01 01:01:20.98' as datetime), cast('2023-01-01 01:01:20.98' as datetime)) +go +~~ERROR (Code: 155)~~ + +~~ERROR (Message: 'fakeoption' is not a recognized datediff option)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT DATEDIFF_BIG(nanosecond, cast('1900-01-01 01:01:20.98' as datetime), cast('3000-01-01 01:01:20.98' as datetime)) +go +~~ERROR (Code: 535)~~ + +~~ERROR (Message: The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO + +begin transaction +go + +SELECT DATEADD(YY,-30000000, cast('1900-01-01' as datetime)); +go +~~ERROR (Code: 517)~~ + +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ + + +if (@@trancount > 0) select cast('compile time error' as text) else select cast('runtime error' as text) +GO +~~START~~ +text +compile time error +~~END~~ + + +if (@@trancount > 0) rollback tran +GO diff --git a/test/JDBC/expected/datediff_internal_date-vu-cleanup.out b/test/JDBC/expected/datediff_internal_date-before-14_10-or-15_5-vu-cleanup.out similarity index 100% rename from test/JDBC/expected/datediff_internal_date-vu-cleanup.out rename to test/JDBC/expected/datediff_internal_date-before-14_10-or-15_5-vu-cleanup.out diff --git a/test/JDBC/expected/datediff_internal_date-vu-prepare.out b/test/JDBC/expected/datediff_internal_date-before-14_10-or-15_5-vu-prepare.out similarity index 100% rename from test/JDBC/expected/datediff_internal_date-vu-prepare.out rename to test/JDBC/expected/datediff_internal_date-before-14_10-or-15_5-vu-prepare.out diff --git a/test/JDBC/expected/datediff_internal_date-vu-verify.out b/test/JDBC/expected/datediff_internal_date-before-14_10-or-15_5-vu-verify.out similarity index 100% rename from test/JDBC/expected/datediff_internal_date-vu-verify.out rename to test/JDBC/expected/datediff_internal_date-before-14_10-or-15_5-vu-verify.out 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/datetimeoffset-timezone-before-15_3-vu-cleanup.out b/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-cleanup.out new file mode 100644 index 0000000000..08d6a6a473 --- /dev/null +++ b/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-cleanup.out @@ -0,0 +1,5 @@ +drop table gh_1412_t1; +GO + +drop view gh_1412_v1; +GO diff --git a/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-prepare.out b/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-prepare.out new file mode 100644 index 0000000000..829cf18db8 --- /dev/null +++ b/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-prepare.out @@ -0,0 +1,46 @@ +SELECT set_config('timezone', 'Australia/Sydney', false) +GO +~~START~~ +text +Australia/Sydney +~~END~~ + + +select current_setting('TIMEZONE'); +GO +~~START~~ +text +Australia/Sydney +~~END~~ + +drop table if exists gh_1412_t1; +GO +create table gh_1412_t1 +( +id int, +dto datetimeoffset, +dto_default datetimeoffset default '2000-06-01 00:00:00', +comment varchar(100) +); +GO +insert gh_1412_t1 values (1, '2000-06-01 00:00:00', default, 'custom time zone'); +GO +~~ROW COUNT: 1~~ + +drop view if exists gh_1412_v1; +GO +create view gh_1412_v1 as select cast('2000-06-01 00:00:00' as datetimeoffset) as dto; +GO + +SELECT set_config('timezone', 'UTC', false) +GO +~~START~~ +text +UTC +~~END~~ + + +insert gh_1412_t1 values (2, '2000-06-01 00:00:00', default, 'default time zone'); +GO +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-verify.out b/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-verify.out new file mode 100644 index 0000000000..4a79db96b9 --- /dev/null +++ b/test/JDBC/expected/datetimeoffset-timezone-before-15_3-vu-verify.out @@ -0,0 +1,65 @@ +SELECT set_config('timezone', 'Australia/Sydney', false) +GO +~~START~~ +text +Australia/Sydney +~~END~~ + + +select current_setting('TIMEZONE'); +GO +~~START~~ +text +Australia/Sydney +~~END~~ + +insert gh_1412_t1 values (3, '2000-06-01 00:00:00', default, 'custom time zone after update'); +GO +~~ROW COUNT: 1~~ + +select * from gh_1412_t1 order by id; +GO +~~START~~ +int#!#datetimeoffset#!#datetimeoffset#!#varchar +1#!#2000-06-01 00:00:00.0000000 +10:00#!#2000-06-01 00:00:00.0000000 +10:00#!#custom time zone +2#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +10:00#!#default time zone +3#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +10:00#!#custom time zone after update +~~END~~ + +select * from gh_1412_v1; +GO +~~START~~ +datetimeoffset +2000-06-01 00:00:00.0000000 +10:00 +~~END~~ + + +SELECT set_config('timezone', 'UTC', false) +GO +~~START~~ +text +UTC +~~END~~ + + +insert gh_1412_t1 values (4, '2000-06-01 00:00:00', default, 'default time zone after update'); +GO +~~ROW COUNT: 1~~ + +select * from gh_1412_t1 order by id; +GO +~~START~~ +int#!#datetimeoffset#!#datetimeoffset#!#varchar +1#!#2000-06-01 00:00:00.0000000 +10:00#!#2000-06-01 00:00:00.0000000 +10:00#!#custom time zone +2#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +10:00#!#default time zone +3#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +10:00#!#custom time zone after update +4#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +10:00#!#default time zone after update +~~END~~ + +select * from gh_1412_v1; +GO +~~START~~ +datetimeoffset +2000-06-01 00:00:00.0000000 +10:00 +~~END~~ + diff --git a/test/JDBC/expected/datetimeoffset-timezone-vu-cleanup.out b/test/JDBC/expected/datetimeoffset-timezone-vu-cleanup.out new file mode 100644 index 0000000000..08d6a6a473 --- /dev/null +++ b/test/JDBC/expected/datetimeoffset-timezone-vu-cleanup.out @@ -0,0 +1,5 @@ +drop table gh_1412_t1; +GO + +drop view gh_1412_v1; +GO diff --git a/test/JDBC/expected/datetimeoffset-timezone-vu-prepare.out b/test/JDBC/expected/datetimeoffset-timezone-vu-prepare.out new file mode 100644 index 0000000000..829cf18db8 --- /dev/null +++ b/test/JDBC/expected/datetimeoffset-timezone-vu-prepare.out @@ -0,0 +1,46 @@ +SELECT set_config('timezone', 'Australia/Sydney', false) +GO +~~START~~ +text +Australia/Sydney +~~END~~ + + +select current_setting('TIMEZONE'); +GO +~~START~~ +text +Australia/Sydney +~~END~~ + +drop table if exists gh_1412_t1; +GO +create table gh_1412_t1 +( +id int, +dto datetimeoffset, +dto_default datetimeoffset default '2000-06-01 00:00:00', +comment varchar(100) +); +GO +insert gh_1412_t1 values (1, '2000-06-01 00:00:00', default, 'custom time zone'); +GO +~~ROW COUNT: 1~~ + +drop view if exists gh_1412_v1; +GO +create view gh_1412_v1 as select cast('2000-06-01 00:00:00' as datetimeoffset) as dto; +GO + +SELECT set_config('timezone', 'UTC', false) +GO +~~START~~ +text +UTC +~~END~~ + + +insert gh_1412_t1 values (2, '2000-06-01 00:00:00', default, 'default time zone'); +GO +~~ROW COUNT: 1~~ + diff --git a/test/JDBC/expected/datetimeoffset-timezone-vu-verify.out b/test/JDBC/expected/datetimeoffset-timezone-vu-verify.out new file mode 100644 index 0000000000..5f82ff57fd --- /dev/null +++ b/test/JDBC/expected/datetimeoffset-timezone-vu-verify.out @@ -0,0 +1,213 @@ +SELECT set_config('timezone', 'Australia/Sydney', false) +GO +~~START~~ +text +Australia/Sydney +~~END~~ + + +select current_setting('TIMEZONE'); +GO +~~START~~ +text +Australia/Sydney +~~END~~ + +insert gh_1412_t1 values (3, '2000-06-01 00:00:00', default, 'custom time zone after update'); +GO +~~ROW COUNT: 1~~ + +select * from gh_1412_t1 order by id; +GO +~~START~~ +int#!#datetimeoffset#!#datetimeoffset#!#varchar +1#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#custom time zone +2#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#default time zone +3#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#custom time zone after update +~~END~~ + +select * from gh_1412_v1; +GO +~~START~~ +datetimeoffset +2000-06-01 00:00:00.0000000 +00:00 +~~END~~ + +-- time zone in plus op with months (input months or years, fixed in gh#1418) +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(1, 0); +GO +~~START~~ +datetimeoffset +2001-06-01 00:00:00.0000000 +00:00 +~~END~~ + +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 1); +GO +~~START~~ +datetimeoffset +2000-07-01 00:00:00.0000000 +00:00 +~~END~~ + +-- time zone in plus op with days (input days or weeks, fixed in gh#1418) +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 0, 1, 0); +GO +~~START~~ +datetimeoffset +2000-06-08 00:00:00.0000000 +00:00 +~~END~~ + +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 0, 0, 1); +GO +~~START~~ +datetimeoffset +2000-06-02 00:00:00.0000000 +00:00 +~~END~~ + +-- time zone in plus op with time (just in case) +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 0, 0, 0, 1, 1); +GO +~~START~~ +datetimeoffset +2000-06-01 01:01:00.0000000 +00:00 +~~END~~ + +-- time zone in type conversion (date conversion fixed in gh#1418) +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as time); +GO +~~START~~ +time +23:01:00.0000000 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as date); +GO +~~START~~ +date +2000-06-01 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as smalldatetime); +GO +~~START~~ +smalldatetime +2000-06-01 23:01:00.0 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as datetime); +GO +~~START~~ +datetime +2000-06-01 23:01:00.0 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as datetime2); +GO +~~START~~ +datetime2 +2000-06-01 23:01:00.0000000 +~~END~~ + + +SELECT set_config('timezone', 'UTC', false) +GO +~~START~~ +text +UTC +~~END~~ + + +insert gh_1412_t1 values (4, '2000-06-01 00:00:00', default, 'default time zone after update'); +GO +~~ROW COUNT: 1~~ + +select * from gh_1412_t1 order by id; +GO +~~START~~ +int#!#datetimeoffset#!#datetimeoffset#!#varchar +1#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#custom time zone +2#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#default time zone +3#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#custom time zone after update +4#!#2000-06-01 00:00:00.0000000 +00:00#!#2000-06-01 00:00:00.0000000 +00:00#!#default time zone after update +~~END~~ + +select * from gh_1412_v1; +GO +~~START~~ +datetimeoffset +2000-06-01 00:00:00.0000000 +00:00 +~~END~~ + +-- time zone in plus op with months (input months or years, fixed in gh#1418) +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(1, 0); +GO +~~START~~ +datetimeoffset +2001-06-01 00:00:00.0000000 +00:00 +~~END~~ + +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 1); +GO +~~START~~ +datetimeoffset +2000-07-01 00:00:00.0000000 +00:00 +~~END~~ + +-- time zone in plus op with days (input days or weeks, fixed in gh#1418) +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 0, 1, 0); +GO +~~START~~ +datetimeoffset +2000-06-08 00:00:00.0000000 +00:00 +~~END~~ + +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 0, 0, 1); +GO +~~START~~ +datetimeoffset +2000-06-02 00:00:00.0000000 +00:00 +~~END~~ + +-- time zone in plus op with time (just in case) +select cast('2000-06-01 00:00:00 +00' as datetimeoffset) + make_interval(0, 0, 0, 0, 1, 1); +GO +~~START~~ +datetimeoffset +2000-06-01 01:01:00.0000000 +00:00 +~~END~~ + +-- time zone in type conversion (date conversion fixed in gh#1418) +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as time); +GO +~~START~~ +time +23:01:00.0000000 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as date); +GO +~~START~~ +date +2000-06-01 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as smalldatetime); +GO +~~START~~ +smalldatetime +2000-06-01 23:01:00.0 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as datetime); +GO +~~START~~ +datetime +2000-06-01 23:01:00.0 +~~END~~ + +select cast(cast('2000-06-01 23:01:00 +00' as datetimeoffset) as datetime2); +GO +~~START~~ +datetime2 +2000-06-01 23:01:00.0000000 +~~END~~ + diff --git a/test/JDBC/expected/default_params-vu-cleanup.out b/test/JDBC/expected/default_params-vu-cleanup.out new file mode 100644 index 0000000000..fe3bae0974 --- /dev/null +++ b/test/JDBC/expected/default_params-vu-cleanup.out @@ -0,0 +1,20 @@ +drop function default_params_func1; +GO + +drop function default_params_func2; +GO + +drop function default_params_func3; +GO + +drop procedure default_params_proc1; +GO + +drop procedure default_params_proc2; +GO + +drop procedure default_params_proc3 +GO + +drop procedure default_params_proc4 +GO diff --git a/test/JDBC/expected/default_params-vu-prepare.out b/test/JDBC/expected/default_params-vu-prepare.out new file mode 100644 index 0000000000..10c39f6ebb --- /dev/null +++ b/test/JDBC/expected/default_params-vu-prepare.out @@ -0,0 +1,21 @@ +create function default_params_func1 (@p1 int=1,@p2 int = 2 ) returns int as begin return @p1 + @p2 end; +GO + +create function default_params_func2 (@p1 int,@p2 int =2, @p3 int) returns int as begin return @p1 + @p2 + @p3 end; +GO + +create function default_params_func3 (@p1 varchar(20) = 'abc') returns varchar as begin return @p1 end; +GO + +create proc default_params_proc1 @p1 int=1, @p2 int=2, @p3 int=3 as select @p1, @p2, @p3 +GO + + +create proc default_params_proc2 (@p1 varchar(20) = 'abc', @p2 int) as select @p1, @p2 +GO + +create proc default_params_proc3 (@p1 varchar = 'abc', @p2 int) as select @p1, @p2 +GO + +create proc default_params_proc4 @p1 int=1, @p2 int=2, @p3 varchar(20)='dbb' as select @p1, @p2, @p3 +GO diff --git a/test/JDBC/expected/default_params-vu-verify.out b/test/JDBC/expected/default_params-vu-verify.out new file mode 100644 index 0000000000..1f7a3cbc96 --- /dev/null +++ b/test/JDBC/expected/default_params-vu-verify.out @@ -0,0 +1,143 @@ +select default_params_func1(default, default); +GO +~~START~~ +int +3 +~~END~~ + + +select default_params_func1(10, default); +GO +~~START~~ +int +12 +~~END~~ + + +select default_params_func1(10); +GO +~~START~~ +int +12 +~~END~~ + + +select default_params_func1(); +GO +~~START~~ +int +3 +~~END~~ + + +select default_params_func1(default); +GO +~~START~~ +int +3 +~~END~~ + + +select default_params_func2(10,default,20); +GO +~~START~~ +int +32 +~~END~~ + + +select default_params_func2(10,20,30); +GO +~~START~~ +int +60 +~~END~~ + + +select default_params_func3(default); +go +~~START~~ +varchar +a +~~END~~ + + +select default_params_func3(); +GO +~~START~~ +varchar +a +~~END~~ + + +select default_params_func3('dddd'); +GO +~~START~~ +varchar +d +~~END~~ + + +exec default_params_proc1 111, default, 333 +GO +~~START~~ +int#!#int#!#int +111#!#2#!#333 +~~END~~ + + +exec default_params_proc1 default, default, default +GO +~~START~~ +int#!#int#!#int +1#!#2#!#3 +~~END~~ + + +exec default_params_proc1 default +GO +~~START~~ +int#!#int#!#int +1#!#2#!#3 +~~END~~ + + +exec default_params_proc2 default, 2 +GO +~~START~~ +varchar#!#int +abc#!#2 +~~END~~ + + +exec default_params_proc2 'dddd', 2 +GO +~~START~~ +varchar#!#int +dddd#!#2 +~~END~~ + + +exec default_params_proc3 default, 2 +GO +~~START~~ +varchar#!#int +a#!#2 +~~END~~ + + +exec default_params_proc3 'dddd', 3 +GO +~~START~~ +varchar#!#int +d#!#3 +~~END~~ + + +exec default_params_proc4 1,2,default +GO +~~START~~ +int#!#int#!#varchar +1#!#2#!#dbb +~~END~~ + diff --git a/test/JDBC/expected/doublequoted_string-vu-verify.out b/test/JDBC/expected/doublequoted_string-vu-verify.out new file mode 100644 index 0000000000..695c4050a2 --- /dev/null +++ b/test/JDBC/expected/doublequoted_string-vu-verify.out @@ -0,0 +1,1627 @@ + +-- BABEL-2442: Handle embedded double quotes in a double-quoted string +-- BABEL-4387: Support double-quoted strings containing single-quote +-- This also exercises parts of the ANTLR parse tree rewriting +set quoted_identifier off +go +create procedure dubquote_p @p varchar(20) = "ab'cd" , @p2 varchar(20)='xyz' +as select @p +go +create procedure dubquote_p2 @p varchar(20) = "ab""cd" +as select @p +go + +set quoted_identifier off +go +select "aBc" +go +~~START~~ +varchar +aBc +~~END~~ + +exec dubquote_p +go +~~START~~ +varchar +ab'cd +~~END~~ + +exec dubquote_p2 +go +~~START~~ +varchar +ab"cd +~~END~~ + +exec dubquote_p "aBc" +go +~~START~~ +varchar +aBc +~~END~~ + +exec dubquote_p 'aBc' +go +~~START~~ +varchar +aBc +~~END~~ + +exec dubquote_p aBc +go +~~START~~ +varchar +aBc +~~END~~ + + +set quoted_identifier on +go +select "aBc" +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "abc" does not exist)~~ + +exec dubquote_p +go +~~START~~ +varchar +ab'cd +~~END~~ + +exec dubquote_p2 +go +~~START~~ +varchar +ab"cd +~~END~~ + +exec dubquote_p "aBc" +go +~~START~~ +varchar +aBc +~~END~~ + +exec dubquote_p 'aBc' +go +~~START~~ +varchar +aBc +~~END~~ + +exec dubquote_p aBc +go +~~START~~ +varchar +aBc +~~END~~ + + +set quoted_identifier off +go +select "ab""cd" +go +~~START~~ +varchar +ab"cd +~~END~~ + +select "de'fg" +go +~~START~~ +varchar +de'fg +~~END~~ + +select 'ab"cd' +go +~~START~~ +varchar +ab"cd +~~END~~ + +select "ab'cd" +go +~~START~~ +varchar +ab'cd +~~END~~ + +select 'ab"cd' +go +~~START~~ +varchar +ab"cd +~~END~~ + +select 'ab"''"''"cd' +go +~~START~~ +varchar +ab"'"'"cd +~~END~~ + +select """" +go +~~START~~ +varchar +" +~~END~~ + +select '''' +go +~~START~~ +varchar +' +~~END~~ + +select '"' +go +~~START~~ +varchar +" +~~END~~ + +select '""' +go +~~START~~ +varchar +"" +~~END~~ + +select "'" +go +~~START~~ +varchar +' +~~END~~ + +select "''" +go +~~START~~ +varchar +'' +~~END~~ + +select """'""'""" +go +~~START~~ +varchar +"'"'" +~~END~~ + + +set quoted_identifier on +go +exec dubquote_p +go +~~START~~ +varchar +ab'cd +~~END~~ + +exec dubquote_p "xx'yy" +go +~~START~~ +varchar +xx'yy +~~END~~ + +exec dubquote_p 'xX"yY' +go +~~START~~ +varchar +xX"yY +~~END~~ + +exec dubquote_p """" +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p '''' +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p '"' +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p '""' +go +~~START~~ +varchar +"" +~~END~~ + +exec dubquote_p "'" +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p "''" +go +~~START~~ +varchar +'' +~~END~~ + +exec dubquote_p """'""'""" +go +~~START~~ +varchar +"'"'" +~~END~~ + + +-- same as above but with named notation +exec dubquote_p @p="xx'yy" , @p2='x"y' +go +~~START~~ +varchar +xx'yy +~~END~~ + +exec dubquote_p @p='xX"yY' , @p2="x""y" +go +~~START~~ +varchar +xX"yY +~~END~~ + +exec dubquote_p @p="""" , @p2="x'y" +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p @p='''' , @p2="x''y" +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p @p='"' , @p2="x''y" +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p @p='""' , @p2="x''y" +go +~~START~~ +varchar +"" +~~END~~ + +exec dubquote_p @p="'" , @p2="x''y" +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p @p="''" , @p2="x''y" +go +~~START~~ +varchar +'' +~~END~~ + +exec dubquote_p @p="""'""'""" , @p2="x''y" +go +~~START~~ +varchar +"'"'" +~~END~~ + + +-- using N'...' notation: +exec dubquote_p N'xX"yY' +go +~~START~~ +varchar +xX"yY +~~END~~ + +exec dubquote_p N'''' +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p N'"' +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p N'""' +go +~~START~~ +varchar +"" +~~END~~ + +exec dubquote_p @p=N'xX"yY' +go +~~START~~ +varchar +xX"yY +~~END~~ + +exec dubquote_p @p=N'''' +go +~~START~~ +varchar +' +~~END~~ + +exec dubquote_p @p=N'"' +go +~~START~~ +varchar +" +~~END~~ + +exec dubquote_p @p=N'""' +go +~~START~~ +varchar +"" +~~END~~ + + +-- functions +set quoted_identifier off +go +create function dubquote_f1(@p varchar(20) = "ab'cd") returns varchar(20) as begin return @p end +go +create function dubquote_f2(@p varchar(20) = "ab""cd") returns varchar(20) as begin return @p end +go +create function dubquote_f3(@p varchar(20) = aBcd) returns varchar(20) as begin return @p end +go +declare @v varchar(20) +exec @v = dubquote_f1 +select @v +go +~~START~~ +varchar +ab'cd +~~END~~ + +declare @v varchar(20) +exec @v = dubquote_f2 +select @v +go +~~START~~ +varchar +ab"cd +~~END~~ + +declare @v varchar(20) +exec @v = dubquote_f3 +select @v +go +~~START~~ +varchar +aBcd +~~END~~ + + +select dbo.dubquote_f1("ab'cd") +go +~~START~~ +varchar +ab'cd +~~END~~ + +select dbo.dubquote_f1('ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1(N'ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1("ab""cd") +go +~~START~~ +varchar +ab"cd +~~END~~ + + +set quoted_identifier on +go +select dbo.dubquote_f1("ab'cd") +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "ab'cd" does not exist)~~ + +select dbo.dubquote_f1('ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1(N'ab"cd') +go +~~START~~ +varchar +ab"cd +~~END~~ + +select dbo.dubquote_f1("ab""cd") +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "ab"cd" does not exist)~~ + + +set quoted_identifier off +go +create procedure dubquote_p2a @p varchar(20) ="aBc" as select @p +go +exec dubquote_p2a +go +~~START~~ +varchar +aBc +~~END~~ + +create procedure dubquote_p3 @p varchar(20) ="'aBc'" as select @p +go +exec dubquote_p3 +go +~~START~~ +varchar +'aBc' +~~END~~ + +declare @v varchar(40) set @v = "It's almost ""weekend""!" select @v +go +~~START~~ +varchar +It's almost "weekend"! +~~END~~ + + +select 'aBc' +go +~~START~~ +varchar +aBc +~~END~~ + +select "aBc" +go +~~START~~ +varchar +aBc +~~END~~ + +select "a'b""c''''''''''d" +go +~~START~~ +varchar +a'b"c''''''''''d +~~END~~ + +select "a'b""c'd" +go +~~START~~ +varchar +a'b"c'd +~~END~~ + +select "'aBc'",'xyz' +go +~~START~~ +varchar#!#varchar +'aBc'#!#xyz +~~END~~ + + +declare @v varchar(20) = 'aBc' select @v +go +~~START~~ +varchar +aBc +~~END~~ + +declare @v varchar(20) = "aBc" select @v +go +~~START~~ +varchar +aBc +~~END~~ + +declare @v varchar(20) = "'a""bc'" select @v +go +~~START~~ +varchar +'a"bc' +~~END~~ + +declare @v varchar(20) select @v = "aBc" select @v +go +~~START~~ +varchar +aBc +~~END~~ + +declare @v varchar(20) = 'x' select @v += "aBc" select @v +go +~~START~~ +varchar +xaBc +~~END~~ + +declare @v varchar(20) select @v = "'a""bc'" select @v +go +~~START~~ +varchar +'a"bc' +~~END~~ + +declare @v varchar(20) = 'x' select @v += "'a""bc'" select @v +go +~~START~~ +varchar +x'a"bc' +~~END~~ + +declare @v varchar(20) set @v = "'a""bc'" select @v +go +~~START~~ +varchar +'a"bc' +~~END~~ + +declare @v varchar(20) = 'x' set @v += "'a""bc'" select @v +go +~~START~~ +varchar +x'a"bc' +~~END~~ + + +declare @v varchar(20) ="aBc" , @v2 varchar(10) = 'xyz' select @v +go +~~START~~ +varchar +aBc +~~END~~ + +declare @v varchar(20), @v2 varchar(20) select @v="a""b''c'd", @v2="x""y''z" select @v, @v2 +go +~~START~~ +varchar#!#varchar +a"b''c'd#!#x"y''z +~~END~~ + +declare @v varchar(20) = "ABC", @v2 varchar(20)="XYZ" select @v+="a""b''c'd", @v2+="x""y''z" select @v, @v2 +go +~~START~~ +varchar#!#varchar +ABCa"b''c'd#!#XYZx"y''z +~~END~~ + +declare @v varchar(20) = "ABC", @v2 varchar(20)="XYZ" set @v+="a""b''c'd" set @v2+="x""y''z" select @v, @v2 +go +~~START~~ +varchar#!#varchar +ABCa"b''c'd#!#XYZx"y''z +~~END~~ + +declare @v varchar(20) ="a""bc" , @v2 varchar(10) = 'x''z' select @v, @v2 +go +~~START~~ +varchar#!#varchar +a"bc#!#x'z +~~END~~ + +declare @v varchar(20) ="a""bc" , @v2 varchar(10) = 'x''z' , @v3 varchar(10) = "x""y'z'z" select @v, @v2, @v3 +go +~~START~~ +varchar#!#varchar#!#varchar +a"bc#!#x'z#!#x"y'z'z +~~END~~ + + +-- bracketed identifiers containing double-quoted strings should not be affected by double-quoted string replacement +-- this SELECT should return 0 rows and no error +create table dubquote_t1([x"a'b"y] int, c varchar(20)) +go +select [x"a'b"y] from dubquote_t1 where c = "a'b" +go +~~START~~ +int +~~END~~ + + +set quoted_identifier off +go +-- the JDBC test cases do not capture PRINT output, but including them here for when it will +print "aBc" +go +print "'aBc'" +go +print "a""b'c" +go +print "a""b'c," + session_user + ",d""e'f," + system_user +go + /*test*/ print "aBc" +go + /*hello*/ print /*hello*/ "aBc" +go +print /*hello*/ "a""b'c," + /*hello*/ +session_user + /*hello*/ +",d""e'f," + /*hello*/ system_user +go +RAISERROR("Message from RAISERROR", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Message from RAISERROR)~~ + +RAISERROR("'Message from RAISERROR'", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: 'Message from RAISERROR')~~ + +RAISERROR("""Message from ""'RAISERROR'""", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: "Message from "'RAISERROR'")~~ + + /*test*/RAISERROR( /*hello*/"Message from 'RAISERROR'", 16,1) +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Message from 'RAISERROR')~~ + + +-- RAISERROR arguments are not yet rewritten. this should raise an error +RAISERROR ('%s %s', 10, 1, 'aBc', "def"); +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "def" does not exist)~~ + + + +declare @v varchar(20) = "a""b'c" +if @v = 'a"b''c' select 'correct' +else select 'wrong' +go +~~START~~ +varchar +correct +~~END~~ + + +declare @v varchar(20) = "a""b'c" +while @v = 'a"b''c' +begin +select 'correct' +break +end +go +~~START~~ +varchar +correct +~~END~~ + + +declare @v varchar(20) = system_user +if @v = system_user select 'correct' +else select 'wrong' +go +~~START~~ +varchar +correct +~~END~~ + + +declare @v varchar(20) = system_user +while @v = system_user +begin +select 'correct' +break +end +go +~~START~~ +varchar +correct +~~END~~ + + +set quoted_identifier on +go +print "aBc" +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "abc" does not exist)~~ + +RAISERROR("Message from RAISERROR", 16,1) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '"Message from RAISERROR"' at line 1 and character position 10)~~ + + +set quoted_identifier off +go +create procedure dubquote_p4 @p varchar(20) ="a'bc" as select @p,@p +go +exec dubquote_p4 +go +~~START~~ +varchar#!#varchar +a'bc#!#a'bc +~~END~~ + +exec dubquote_p4 "aBc" +go +~~START~~ +varchar#!#varchar +aBc#!#aBc +~~END~~ + +exec dubquote_p4 "ab""cd" +go +~~START~~ +varchar#!#varchar +ab"cd#!#ab"cd +~~END~~ + +exec dubquote_p4 "ab'cd" +go +~~START~~ +varchar#!#varchar +ab'cd#!#ab'cd +~~END~~ + +select "ab'cd" +go +~~START~~ +varchar +ab'cd +~~END~~ + +create function dubquote_f4 (@p varchar(20) = "'aBc'") returns varchar(50) as begin return ((("function's return" +( " string value:" ))) +"'" + @p + "'") end +go +select dbo.dubquote_f4("x") +go +~~START~~ +varchar +function's return string value:'x' +~~END~~ + + +create function dubquote_f5 () returns varchar(50) as begin return "a""b'c" end +go +select dbo.dubquote_f5() +go +~~START~~ +varchar +a"b'c +~~END~~ + + +create function dubquote_f6 () returns varchar(50) as begin return "a""b'c," + session_user + ",d""e'f," + system_user end +go +select dbo.dubquote_f6() +go +~~START~~ +varchar +a"b'c,dbo,d"e'f,jdbc_user +~~END~~ + + +CREATE function dubquote_f7() returns varchar(30) as begin return system_user end +go +select dbo.dubquote_f7(), system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + + +create procedure dubquote_p5 @p varchar(10) as select @p +go +exec dubquote_p5 'xyz' exec dubquote_p5 aBc +go +~~START~~ +varchar +xyz +~~END~~ + +~~START~~ +varchar +aBc +~~END~~ + +exec dubquote_p5 aBcd +go +~~START~~ +varchar +aBcd +~~END~~ + +exec dubquote_p5 [aBcd] +go +~~START~~ +varchar +aBcd +~~END~~ + +exec dubquote_p5 @p=aBcde +go +~~START~~ +varchar +aBcde +~~END~~ + +declare @v varchar(20) exec dubquote_p5 @v +go +~~START~~ +varchar + +~~END~~ + +declare @v varchar(20) = 'efg' exec dubquote_p5 @v +go +~~START~~ +varchar +efg +~~END~~ + +declare @v varchar(20) exec dubquote_p5 @p=@v +go +~~START~~ +varchar + +~~END~~ + +declare @v varchar(20) = 'hij' exec dubquote_p5 @p=@v +go +~~START~~ +varchar +hij +~~END~~ + + +declare @v varchar(20) = session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +dbo#!#dbo +~~END~~ + +declare @v varchar(20) = 'aBc' + session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +aBcdbo#!#dbo +~~END~~ + +declare @v varchar(20) = "aBc" + session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +aBcdbo#!#dbo +~~END~~ + +declare @v varchar(20) = "ab""c'd" + session_user select @v, session_user +go +~~START~~ +varchar#!#nvarchar +ab"c'ddbo#!#dbo +~~END~~ + + +declare @v varchar(20) = system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = 'aBc' + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +aBcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "aBc" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +aBcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "ab""c'd" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab"c'djdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = 'aBc' + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +aBcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = "aBc" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +aBcjdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = "ab""c'd" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab"c'djdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = '' set @v = "ab""c'd" + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab"c'djdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(20) = 'ab,' set @v += system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +ab,jdbc_user#!#jdbc_user +~~END~~ + +declare @myvar varchar(20) = '' set @myvar += system_user select @myvar, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user#!#jdbc_user +~~END~~ + + +/*hello*/declare @myvar varchar(50) = '' /*hello*/set /*hello*/@myvar/*hello*/ += +/*hello*/system_user/*hello*/ + +/*hello*/",a""b'c," + /*hello*/system_user +select @myvar, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user,a"b'c,jdbc_user#!#jdbc_user +~~END~~ + +declare @v varchar(50) = system_user+"," set @v += "a""b'c," + system_user + ",a""b'c," + system_user select @v, system_user +go +~~START~~ +varchar#!#nvarchar +jdbc_user,a"b'c,jdbc_user,a"b'c,jdbc_user#!#jdbc_user +~~END~~ + + +-- all in one batch: +declare @v varchar(20) = session_user select @v +declare @v1 varchar(20) = 'aBc' + session_user select @v1 +declare @v2 varchar(20) = "ab""c'd" + session_user select @v2 +declare @v3 varchar(20) ="a""bc" , @v4 varchar(20) = 'x''z' select @v3,@v4 +declare @v5 varchar(20) ="a""bc" , @v6 varchar(20) = 'x''z' , @v7 varchar(20) = "x""y'z'z" select @v5, @v6, @v7 +go +~~START~~ +varchar +dbo +~~END~~ + +~~START~~ +varchar +aBcdbo +~~END~~ + +~~START~~ +varchar +ab"c'ddbo +~~END~~ + +~~START~~ +varchar#!#varchar +a"bc#!#x'z +~~END~~ + +~~START~~ +varchar#!#varchar#!#varchar +a"bc#!#x'z#!#x"y'z'z +~~END~~ + + +declare @v varchar(20) = session_user, @v2 varchar(20)= system_user select @v, @v2, session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +dbo#!#jdbc_user#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = 'aBcd' + session_user, @v2 varchar(20) = 'xy' + session_user select @v, @v2, session_user +go +~~START~~ +varchar#!#varchar#!#nvarchar +aBcddbo#!#xydbo#!#dbo +~~END~~ + +declare @v varchar(20) = 'aBcd' + upper('x'), @v2 varchar(20) = 'xy' + upper('y') select @v, @v2 +go +~~START~~ +varchar#!#varchar +aBcdX#!#xyY +~~END~~ + +declare @v varchar(20) = session_user, @v2 varchar(20)= system_user select @v,@v2,session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +dbo#!#jdbc_user#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "x'y" + session_user, @v2 varchar(20)= "a'b" + system_user select @v,@v2,session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +x'ydbo#!#a'bjdbc_user#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = "x'y" + session_user, @v2 varchar(20)= "a'b" + system_user + "x''""" select @v,@v2,session_user, system_user +go +~~START~~ +varchar#!#varchar#!#nvarchar#!#nvarchar +x'ydbo#!#a'bjdbc_userx''"#!#dbo#!#jdbc_user +~~END~~ + +declare @v varchar(20) = session_user select @v +go +~~START~~ +varchar +dbo +~~END~~ + + +create sequence dubquote_myseq +go +create sequence dubquote_myseq2 +go +create sequence dubquote_myseq3 +go +create sequence dubquote_myseq4 +go +declare +@v varchar(20) = '123' + next value for dubquote_myseq, +@v2 varchar(20) = next value for dubquote_myseq2, +@v3 varchar(20) = next value for dubquote_myseq3 + "000", +@v4 varchar(20) = "123" + next value for dubquote_myseq4 + "000" +select @v, @v2, @v3, @v4 +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar +124#!#1#!#1#!#124 +~~END~~ + +declare @v int = next value for dubquote_myseq select @v +go +~~START~~ +int +2 +~~END~~ + +declare @v int = next value for dubquote_myseq select @v +go +~~START~~ +int +3 +~~END~~ + +declare @v int = len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +17 +~~END~~ + +declare @v int = 0 set @v = next value for dubquote_myseq select @v +go +~~START~~ +int +5 +~~END~~ + +declare @v int = 0 set @v += len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +19 +~~END~~ + +declare @v int = 0 set @v -= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +-20 +~~END~~ + +declare @v int = 1 set @v *= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +21 +~~END~~ + +declare @v int = 1 set @v /= len("a'bc") + next value for dubquote_myseq + len(system_user) select @v +go +~~START~~ +int +0 +~~END~~ + + +set quoted_identifier on +go +create procedure dubquote_p6 @p varchar(20) ="aBc" as select @p +go +exec dubquote_p6 +go +~~START~~ +varchar +aBc +~~END~~ + +create procedure dubquote_p7 @p varchar(20) ="'aBc'" as select @p +go +exec dubquote_p7 +go +~~START~~ +varchar +'aBc' +~~END~~ + +declare @v varchar(20) = 'aBc' select @v +go +~~START~~ +varchar +aBc +~~END~~ + + +set quoted_identifier off +go +create procedure dubquote_p8 @p varchar(20) as select @p +go +execute dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +exec dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +execute[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +exec[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +exec ..[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +dbo.dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +.dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +..dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/execute dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/exec dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/execute[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/exec[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/.dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/..dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/.[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/..[dubquote_p8]/*test*/"x'Y""z" +execute dubquote_p8 "a'B""C" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +~~START~~ +varchar +a'B"C +~~END~~ + + +set quoted_identifier on +go +execute dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +exec dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +execute[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +exec[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +exec ..[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +dbo.dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +.dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +..dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/execute dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/exec dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/execute[dubquote_p8]"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/exec[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/.dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/..dubquote_p8 "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/.[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/..[dubquote_p8]/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +"dubquote_p8" "x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/"dubquote_p8"/*test*/"x'Y""z" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +/*test*/"dubquote_p8"/*test*/"x'Y""z" +execute dubquote_p8 "a'B""C" +go +~~START~~ +varchar +x'Y"z +~~END~~ + +~~START~~ +varchar +a'B"C +~~END~~ + + +set quoted_identifier on +go +-- negative tests +declare @v varchar(20) = "aBc" select @v +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "abc" does not exist)~~ + +declare @v varchar(20) = "'aBc'" select @v +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "'abc'" does not exist)~~ + + + +--cleanup +drop procedure dubquote_p +go +drop procedure dubquote_p2 +go +drop function dubquote_f1 +go +drop function dubquote_f2 +go +drop function dubquote_f3 +go +drop procedure dubquote_p2a +go +drop procedure dubquote_p3 +go +drop procedure dubquote_p4 +go +drop function dubquote_f4 +go +drop function dubquote_f5 +go +drop function dubquote_f6 +go +drop function dubquote_f7 +go +drop procedure dubquote_p5 +go +drop sequence dubquote_myseq +go +drop sequence dubquote_myseq2 +go +drop sequence dubquote_myseq3 +go +drop sequence dubquote_myseq4 +go +drop procedure dubquote_p6 +go +drop procedure dubquote_p7 +go +drop procedure dubquote_p8 +go +drop table dubquote_t1 +go diff --git a/test/JDBC/expected/drop_database.out b/test/JDBC/expected/drop_database.out new file mode 100644 index 0000000000..c783fbe25d --- /dev/null +++ b/test/JDBC/expected/drop_database.out @@ -0,0 +1,31 @@ +use master +go + +CREATE DATABASE errdb +GO + +USE errdb +GO + +CREATE SCHEMA Purchasing; +GO + +CREATE TYPE NameType FROM varchar(50); +GO + +CREATE TABLE Purchasing.Vendor(VendorName NameType) +GO + +CREATE TRIGGER dVendor ON Purchasing.Vendor +FOR DELETE AS +BEGIN +RETURN; +END; +GO + +USE master +go + +DROP DATABASE errdb +go + diff --git a/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-cleanup.out b/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-cleanup.out new file mode 100644 index 0000000000..4d1247a5c1 --- /dev/null +++ b/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-cleanup.out @@ -0,0 +1,63 @@ +-- FOR JSON PATH clause without nested support +DROP VIEW forjson_vu_v_people +GO + +DROP VIEW forjson_vu_v_countries +GO + +-- Multiple tables without nested support +DROP VIEW forjson_vu_v_join +GO + +-- ROOT directive without specifying value +DROP VIEW forjson_vu_v_root +GO + +-- ROOT directive with specifying ROOT value +DROP VIEW forjson_vu_v_root_value +GO + +-- ROOT directive with specifying ROOT value with empty string +DROP VIEW forjson_vu_v_empty_root +GO + +-- WITHOUT_ARRAY_WRAPPERS directive +DROP VIEW forjson_vu_v_without_array_wrapper +GO + +-- INCLUDE_NULL_VALUES directive +DROP VIEW forjson_vu_v_include_null_values +GO + +-- Multiple Directives +DROP VIEW forjson_vu_v_root_include_null_values +GO + +DROP VIEW forjson_vu_v_without_array_wrapper_include_null_values +GO + + +-- Test case with parameters +DROP PROCEDURE forjson_vu_p_params1 +GO + +DROP PROCEDURE forjson_vu_p_params2 +GO + +-- All null values test +DROP VIEW forjson_vu_v_nulls +GO + +-- Test for all parser rules +DROP VIEW forjson_vu_v_order_by +GO + +-- Display Table Contents +DROP TABLE forjson_vu_t_people +GO + +DROP TABLE forjson_vu_t_countries +GO + +DROP TABLE forjson_vu_t_values +GO diff --git a/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-prepare.out b/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-prepare.out new file mode 100644 index 0000000000..486838fe84 --- /dev/null +++ b/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-prepare.out @@ -0,0 +1,208 @@ +CREATE TABLE forjson_vu_t_people ( +[Id] INT, +[FirstName] VARCHAR(25), +[LastName] VARCHAR(25), +[State] VARCHAR(25) ) +GO + +INSERT INTO forjson_vu_t_people values +(1,'Divya','Kumar',NULL), +(2,NULL,'Khanna','Bengaluru'), +(3,'Tom','Mehta','Kolkata'), +(4,'Kane',NULL,'Delhi') +GO +~~ROW COUNT: 4~~ + + +CREATE TABLE forjson_vu_t_countries ( +[Id] INT, +[Age] INT, +[Country] VARCHAR(25)) +GO + +INSERT INTO forjson_vu_t_countries values +(1,25, 'India'), +(2,40, 'USA'), +(3,30, 'India'), +(4,20, NULL), +(5,10, 'USA') +GO +~~ROW COUNT: 5~~ + + +CREATE TABLE forjson_vu_t_values ( +[Id] INT, +[value] VARCHAR(25) ) +GO + +INSERT INTO forjson_vu_t_values values +(1,NULL), +(2,NULL), +(3,NULL) +GO +~~ROW COUNT: 3~~ + + +-- FOR JSON PATH clause without nested support +CREATE VIEW forjson_vu_v_people AS +SELECT ( + SELECT Id AS EmpId, + FirstName AS "Name.FirstName", + LastName AS "Name.LastName", + State + FROM forjson_vu_t_people + FOR JSON PATH +) c1 +GO + +CREATE VIEW forjson_vu_v_countries AS +SELECT ( + SELECT Id, + Age, + Country + FROM forjson_vu_t_countries + FOR JSON PATH +) c1 +GO + +-- Multiple tables without nested support +CREATE VIEW forjson_vu_v_join AS +SELECT ( + SELECT E.FirstName AS 'Person.Name', + E.LastName AS 'Person.Surname', + D.Age AS 'Employee.Price', + D.Country AS 'Employee.Quantity' + FROM forjson_vu_t_people E + INNER JOIN forjson_vu_t_countries D + ON E.Id = D.Id + FOR JSON PATH +) c1 +GO + +-- ROOT directive without specifying value +CREATE VIEW forjson_vu_v_root AS +SELECT ( + SELECT FirstName, + LastName + FROM forjson_vu_t_people + FOR JSON PATH, ROOT +) c1 +GO + +-- ROOT directive with specifying ROOT value +CREATE VIEW forjson_vu_v_root_value AS +SELECT ( + SELECT FirstName, + LastName + FROM forjson_vu_t_people + FOR JSON PATH, ROOT('Employee') +) c1 +GO + +-- ROOT directive with specifying ROOT value with empty string +CREATE VIEW forjson_vu_v_empty_root AS +SELECT ( + SELECT FirstName, + LastName + FROM forjson_vu_t_people + FOR JSON PATH, ROOT('') +) c1 +GO + +-- WITHOUT_ARRAY_WRAPPERS directive +CREATE VIEW forjson_vu_v_without_array_wrapper AS +SELECT ( + SELECT FirstName, + LastName + FROM forjson_vu_t_people + FOR JSON PATH, WITHOUT_ARRAY_WRAPPER +) c1 +GO + +-- INCLUDE_NULL_VALUES directive +CREATE VIEW forjson_vu_v_include_null_values AS +SELECT ( + SELECT FirstName, + LastName + FROM forjson_vu_t_people + FOR JSON PATH, INCLUDE_NULL_VALUES +) c1 +GO + +-- Multiple Directives +CREATE VIEW forjson_vu_v_root_include_null_values AS +SELECT ( + SELECT Id, + Age, + Country + FROM forjson_vu_t_countries + FOR JSON PATH, ROOT('Employee'), INCLUDE_NULL_VALUES +) c1 +GO + +CREATE VIEW forjson_vu_v_without_array_wrapper_include_null_values AS +SELECT ( + SELECT Id, + Age, + Country + FROM forjson_vu_t_countries + FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES +) c1 +GO + +-- Throws error as ROOT and WITHOUT_ARRAY_WRAPPER cannot be used together +CREATE VIEW forjson_vu_v_root_and_without_array_wrapper AS +SELECT ( + SELECT Id, + Age, + Country + FROM forjson_vu_t_countries + FOR JSON PATH, ROOT, WITHOUT_ARRAY_WRAPPER +) c1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: ROOT option and WITHOUT_ARRAY_WRAPPER option cannot be used together in FOR JSON. Remove one of these options)~~ + + +-- Test case with parameters +CREATE PROCEDURE forjson_vu_p_params1 @id int AS +SELECT ( + SELECT Firstname AS [Name], + State + FROM forjson_vu_t_people + WHERE Id = @id + FOR JSON PATH +) c1 +GO + +CREATE PROCEDURE forjson_vu_p_params2 @id int AS +SELECT ( + SELECT Firstname AS [nam"@e], + State AS [State"@] + FROM forjson_vu_t_people + WHERE Id = @id + FOR JSON PATH +) c1 +GO + +-- All null values test +CREATE VIEW forjson_vu_v_nulls AS +SELECT ( + SELECT value + FROM forjson_vu_t_values + FOR JSON PATH +) c1 +GO + +-- Test for all parser rules +CREATE VIEW forjson_vu_v_order_by AS +SELECT ( + SELECT Id, + Age, + Country + FROM forjson_vu_t_countries + ORDER BY Age + FOR JSON PATH +) C1 +GO diff --git a/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-verify.out b/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-verify.out new file mode 100644 index 0000000000..9b5f226477 --- /dev/null +++ b/test/JDBC/expected/forjson-before-14_10-or-15_5-vu-verify.out @@ -0,0 +1,157 @@ +-- Display Table Contents +SELECT * FROM forjson_vu_t_people +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar +1#!#Divya#!#Kumar#!# +2#!##!#Khanna#!#Bengaluru +3#!#Tom#!#Mehta#!#Kolkata +4#!#Kane#!##!#Delhi +~~END~~ + + +SELECT * FROM forjson_vu_t_countries +GO +~~START~~ +int#!#int#!#varchar +1#!#25#!#India +2#!#40#!#USA +3#!#30#!#India +4#!#20#!# +5#!#10#!#USA +~~END~~ + + +SELECT * FROM forjson_vu_t_values +GO +~~START~~ +int#!#varchar +1#!# +2#!# +3#!# +~~END~~ + + +-- FOR JSON PATH clause without nested support +SELECT * FROM forjson_vu_v_people +GO +~~START~~ +nvarchar +[{"EmpId":1,"Name.FirstName":"Divya","Name.LastName":"Kumar"},{"EmpId":2,"Name.LastName":"Khanna","State":"Bengaluru"},{"EmpId":3,"Name.FirstName":"Tom","Name.LastName":"Mehta","State":"Kolkata"},{"EmpId":4,"Name.FirstName":"Kane","State":"Delhi"}] +~~END~~ + + +SELECT * FROM forjson_vu_v_countries +GO +~~START~~ +nvarchar +[{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"},{"Id":4,"Age":20},{"Id":5,"Age":10,"Country":"USA"}] +~~END~~ + + +-- Multiple tables without nested support +SELECT * FROM forjson_vu_v_join +GO +~~START~~ +nvarchar +[{"Person.Name":"Divya","Person.Surname":"Kumar","Employee.Price":25,"Employee.Quantity":"India"},{"Person.Surname":"Khanna","Employee.Price":40,"Employee.Quantity":"USA"},{"Person.Name":"Tom","Person.Surname":"Mehta","Employee.Price":30,"Employee.Quantity":"India"},{"Person.Name":"Kane","Employee.Price":20}] +~~END~~ + + +-- ROOT directive without specifying value +SELECT * FROM forjson_vu_v_root +GO +~~START~~ +nvarchar +{"root":[{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"}]} +~~END~~ + + +-- ROOT directive with specifying ROOT value +SELECT * FROM forjson_vu_v_root_value +GO +~~START~~ +nvarchar +{"Employee":[{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"}]} +~~END~~ + + +-- ROOT directive with specifying ROOT value with empty string +SELECT * FROM forjson_vu_v_empty_root +GO +~~START~~ +nvarchar +{"":[{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"}]} +~~END~~ + + +-- WITHOUT_ARRAY_WRAPPERS directive +SELECT * FROM forjson_vu_v_without_array_wrapper +GO +~~START~~ +nvarchar +{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"} +~~END~~ + + +-- INCLUDE_NULL_VALUES directive +SELECT * FROM forjson_vu_v_include_null_values +GO +~~START~~ +nvarchar +[{"FirstName":"Divya","LastName":"Kumar"},{"FirstName":null,"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane","LastName":null}] +~~END~~ + + +-- Multiple Directives +SELECT * FROM forjson_vu_v_root_include_null_values +GO +~~START~~ +nvarchar +{"Employee":[{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"},{"Id":4,"Age":20,"Country":null},{"Id":5,"Age":10,"Country":"USA"}]} +~~END~~ + + +SELECT * FROM forjson_vu_v_without_array_wrapper_include_null_values +GO +~~START~~ +nvarchar +{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"},{"Id":4,"Age":20,"Country":null},{"Id":5,"Age":10,"Country":"USA"} +~~END~~ + + + +-- Test case with parameters +EXECUTE forjson_vu_p_params1 @id = 2 +GO +~~START~~ +nvarchar +[{"State": "Bengaluru"}] +~~END~~ + + +EXECUTE forjson_vu_p_params2 @id = 3 +GO +~~START~~ +nvarchar +[{"nam\"@e": "Tom", "State\"@": "Kolkata"}] +~~END~~ + + +-- All null values test +SELECT * FROM forjson_vu_v_nulls +GO +~~START~~ +nvarchar +[{},{},{}] +~~END~~ + + +-- Test for all parser rules +SELECT * FROM forjson_vu_v_order_by +GO +~~START~~ +nvarchar +[{"Id":5,"Age":10,"Country":"USA"},{"Id":4,"Age":20},{"Id":1,"Age":25,"Country":"India"},{"Id":3,"Age":30,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"}] +~~END~~ + diff --git a/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-cleanup.out b/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-cleanup.out new file mode 100644 index 0000000000..859f23a74e --- /dev/null +++ b/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-cleanup.out @@ -0,0 +1,74 @@ +-- DIFFERENT CASES TO CHECK DATATYPES +-- Exact Numerics +DROP VIEW forjson_datatypes_vu_v_numerics +GO + +DROP VIEW forjson_datatypes_vu_v_bit +GO + +DROP VIEW forjson_datatypes_vu_v_money +GO + +DROP VIEW forjson_datatypes_vu_v_smallmoney +GO + +-- Approximate numerics +DROP VIEW forjson_datatypes_vu_v_approx_numerics +GO + +-- Date and time +DROP VIEW forjson_datatypes_vu_v_time_date +GO + +DROP VIEW forjson_datatypes_vu_v_smalldatetime +GO + +DROP VIEW forjson_datatypes_vu_v_datetime +GO + +DROP VIEW forjson_datatypes_vu_v_datetime2 +GO + +DROP VIEW forjson_datatypes_vu_v_datetimeoffset +GO + +-- Character strings +DROP VIEW forjson_datatypes_vu_v_strings +GO + +-- Unicode character strings +DROP VIEW forjson_datatypes_vu_v_unicode_strings +GO + +-- NULL datetimes +DROP VIEW forjson_datatypes_vu_v_nulldatetime; +go + +DROP VIEW forjson_datatypes_vu_v_nullsmalldatetime; +go + +DROP VIEW forjson_datatypes_vu_v_nulldatetime2; +go + +DROP VIEW forjson_datatypes_vu_v_nulldatetimeoffset; +go + +-- DROP TABLE +DROP TABLE forjson_datatypes_vu_t_exact_numerics +GO + +-- Approximate numerics +DROP TABLE forjson_datatypes_vu_t_approx_numerics +GO + +-- Date and time +DROP TABLE forjson_datatypes_vu_t_date_and_time +GO + +-- Character strings +DROP TABLE forjson_datatypes_vu_t_strings +GO + +-- Unicode character strings +DROP TABLE forjson_datatypes_vu_t_unicode_strings +GO diff --git a/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-prepare.out b/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-prepare.out new file mode 100644 index 0000000000..0f84cd53da --- /dev/null +++ b/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-prepare.out @@ -0,0 +1,182 @@ +-- DIFFERENT CASES TO CHECK DATATYPES +-- Exact Numerics +CREATE TABLE forjson_datatypes_vu_t_exact_numerics(abigint bigint, abit bit, adecimal decimal, aint int, amoney money, anumeric numeric, asmallint smallint, asmallmoney smallmoney, atinyint tinyint) +GO +INSERT forjson_datatypes_vu_t_exact_numerics VALUES(9223372036854775807, 1, 123.2, 2147483647, 3148.29, 12345.12, 32767, 3148.29, 255) +GO +~~ROW COUNT: 1~~ + + +-- Approximate numerics +CREATE TABLE forjson_datatypes_vu_t_approx_numerics(afloat float, areal real) +GO +INSERT forjson_datatypes_vu_t_approx_numerics VALUES(12.05, 120.53) +GO +~~ROW COUNT: 1~~ + + +-- Date and time +CREATE TABLE forjson_datatypes_vu_t_date_and_time(atime time, adate date, asmalldatetime smalldatetime, adatetime datetime, adatetime2 datetime2, adatetimeoffset datetimeoffset, adatetimeoffset_2 datetimeoffset) +GO +INSERT forjson_datatypes_vu_t_date_and_time VALUES('2022-11-11 23:17:08.560','2022-11-11 23:17:08.560','2022-11-11 23:17:08.560','2022-11-11 23:17:08.560','2022-11-11 23:17:08.560','2022-11-11 23:17:08.560', '2012-10-12 12:34:56 +02:30') +GO +~~ROW COUNT: 1~~ + + +-- Character strings +CREATE TABLE forjson_datatypes_vu_t_strings(achar char, avarchar varchar(3), atext text) +GO +INSERT forjson_datatypes_vu_t_strings VALUES('a','abc','abc') +GO +~~ROW COUNT: 1~~ + + +-- Unicode character strings +CREATE TABLE forjson_datatypes_vu_t_unicode_strings(anchar nchar(5), anvarchar nvarchar(5), antext ntext) +GO +INSERT forjson_datatypes_vu_t_unicode_strings VALUES('abc','abc','abc') +GO +~~ROW COUNT: 1~~ + + +-- T-SQL does not allow raw scalars as the output of a view, so surround the FOR JSON call with a SELECT to avoid a syntax error +-- Exact Numerics +CREATE VIEW forjson_datatypes_vu_v_numerics AS +SELECT +( + SELECT abigint, adecimal, aint, anumeric, asmallint, atinyint + FROM forjson_datatypes_vu_t_exact_numerics + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_bit AS +SELECT +( + SELECT abit + FROM forjson_datatypes_vu_t_exact_numerics + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_money AS +SELECT +( + SELECT amoney + FROM forjson_datatypes_vu_t_exact_numerics + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_smallmoney AS +SELECT +( + SELECT asmallmoney + FROM forjson_datatypes_vu_t_exact_numerics + FOR JSON PATH +) as c1; +GO + +-- Approximate numerics +CREATE VIEW forjson_datatypes_vu_v_approx_numerics AS +SELECT +( + SELECT * + FROM forjson_datatypes_vu_t_approx_numerics + FOR JSON PATH +) as c1; +GO + +-- Date and time +CREATE VIEW forjson_datatypes_vu_v_time_date AS +SELECT +( + SELECT atime,adate + FROM forjson_datatypes_vu_t_date_and_time + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_smalldatetime AS +SELECT +( + SELECT asmalldatetime + FROM forjson_datatypes_vu_t_date_and_time + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_datetime AS +SELECT +( + SELECT adatetime + FROM forjson_datatypes_vu_t_date_and_time + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_datetime2 AS +SELECT +( + SELECT adatetime2 + FROM forjson_datatypes_vu_t_date_and_time + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_datetimeoffset AS +SELECT +( + SELECT adatetimeoffset, adatetimeoffset_2 + FROM forjson_datatypes_vu_t_date_and_time + FOR JSON PATH +) as c1; +GO + +-- Character strings +CREATE VIEW forjson_datatypes_vu_v_strings AS +SELECT +( + SELECT * + FROM forjson_datatypes_vu_t_strings + FOR JSON PATH +) as c1; +GO + +-- Unicode character strings +CREATE VIEW forjson_datatypes_vu_v_unicode_strings AS +SELECT +( + SELECT * + FROM forjson_datatypes_vu_t_unicode_strings + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nulldatetime AS +SELECT +( + select cast(null as datetime) for JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nullsmalldatetime AS +SELECT +( + select cast(null as smalldatetime) for JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nulldatetime2 AS +SELECT +( + select cast(null as datetime2) for JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nulldatetimeoffset AS +SELECT +( + select cast(null as datetimeoffset) for JSON PATH +) as c1; +GO diff --git a/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-verify.out b/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-verify.out new file mode 100644 index 0000000000..81d555646a --- /dev/null +++ b/test/JDBC/expected/forjson-datatypes-before-14_10-or-15_5-vu-verify.out @@ -0,0 +1,135 @@ +-- DIFFERENT CASES TO CHECK DATATYPES +-- Exact Numerics +SELECT * FROM forjson_datatypes_vu_v_numerics +GO +~~START~~ +nvarchar +[{"abigint":9223372036854775807,"adecimal":123,"aint":2147483647,"anumeric":12345,"asmallint":32767,"atinyint":255}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_bit +GO +~~START~~ +nvarchar +[{"abit":true}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_money +GO +~~START~~ +nvarchar +[{"amoney":3148.2900}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_smallmoney +GO +~~START~~ +nvarchar +[{"asmallmoney":3148.2900}] +~~END~~ + + +-- Approximate numerics +SELECT * FROM forjson_datatypes_vu_v_approx_numerics +GO +~~START~~ +nvarchar +[{"afloat":12.05,"areal":120.53}] +~~END~~ + + +-- Date and time +SELECT * FROM forjson_datatypes_vu_v_time_date +GO +~~START~~ +nvarchar +[{"atime":"23:17:08.56","adate":"2022-11-11"}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_smalldatetime +GO +~~START~~ +nvarchar +[{"asmalldatetime":"2022-11-11T23:17:00"}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_datetime +GO +~~START~~ +nvarchar +[{"adatetime":"2022-11-11T23:17:08.56"}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_datetime2 +GO +~~START~~ +nvarchar +[{"adatetime2":"2022-11-11T23:17:08.56"}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_datetimeoffset +GO +~~START~~ +nvarchar +[{"adatetimeoffset":"2022-11-11T23:17:08.56Z","adatetimeoffset_2":"2012-10-12T12:34:56+02:30"}] +~~END~~ + + +-- Character strings +SELECT * FROM forjson_datatypes_vu_v_strings +GO +~~START~~ +nvarchar +[{"achar":"a","avarchar":"abc","atext":"abc"}] +~~END~~ + + +-- Unicode character strings +SELECT * FROM forjson_datatypes_vu_v_unicode_strings +GO +~~START~~ +nvarchar +[{"anchar":"abc ","anvarchar":"abc","antext":"abc"}] +~~END~~ + + + +-- NULL datetime and datetimeoffset +SELECT * FROM forjson_datatypes_vu_v_nulldatetime +GO +~~START~~ +nvarchar +[{}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_nullsmalldatetime +GO +~~START~~ +nvarchar +[{}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_nulldatetime2 +GO +~~START~~ +nvarchar +[{}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_nulldatetimeoffset +GO +~~START~~ +nvarchar +[{}] +~~END~~ + diff --git a/test/JDBC/expected/forjson-datatypes-vu-cleanup.out b/test/JDBC/expected/forjson-datatypes-vu-cleanup.out index 927d4de3dc..859f23a74e 100644 --- a/test/JDBC/expected/forjson-datatypes-vu-cleanup.out +++ b/test/JDBC/expected/forjson-datatypes-vu-cleanup.out @@ -40,6 +40,19 @@ GO DROP VIEW forjson_datatypes_vu_v_unicode_strings GO +-- NULL datetimes +DROP VIEW forjson_datatypes_vu_v_nulldatetime; +go + +DROP VIEW forjson_datatypes_vu_v_nullsmalldatetime; +go + +DROP VIEW forjson_datatypes_vu_v_nulldatetime2; +go + +DROP VIEW forjson_datatypes_vu_v_nulldatetimeoffset; +go + -- DROP TABLE DROP TABLE forjson_datatypes_vu_t_exact_numerics GO diff --git a/test/JDBC/expected/forjson-datatypes-vu-prepare.out b/test/JDBC/expected/forjson-datatypes-vu-prepare.out index c33f565fa9..0f84cd53da 100644 --- a/test/JDBC/expected/forjson-datatypes-vu-prepare.out +++ b/test/JDBC/expected/forjson-datatypes-vu-prepare.out @@ -152,3 +152,31 @@ SELECT FOR JSON PATH ) as c1; GO + +CREATE VIEW forjson_datatypes_vu_v_nulldatetime AS +SELECT +( + select cast(null as datetime) for JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nullsmalldatetime AS +SELECT +( + select cast(null as smalldatetime) for JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nulldatetime2 AS +SELECT +( + select cast(null as datetime2) for JSON PATH +) as c1; +GO + +CREATE VIEW forjson_datatypes_vu_v_nulldatetimeoffset AS +SELECT +( + select cast(null as datetimeoffset) for JSON PATH +) as c1; +GO diff --git a/test/JDBC/expected/forjson-datatypes-vu-verify.out b/test/JDBC/expected/forjson-datatypes-vu-verify.out index 539e2fc77d..425eef8bbf 100644 --- a/test/JDBC/expected/forjson-datatypes-vu-verify.out +++ b/test/JDBC/expected/forjson-datatypes-vu-verify.out @@ -4,7 +4,7 @@ SELECT * FROM forjson_datatypes_vu_v_numerics GO ~~START~~ nvarchar -[{"abigint":9223372036854775807,"adecimal":123,"aint":2147483647,"anumeric":12345,"asmallint":32767,"atinyint":255}] +[{"abigint": 9223372036854775807, "adecimal": 123, "aint": 2147483647, "anumeric": 12345, "asmallint": 32767, "atinyint": 255}] ~~END~~ @@ -12,7 +12,7 @@ SELECT * FROM forjson_datatypes_vu_v_bit GO ~~START~~ nvarchar -[{"abit":true}] +[{"abit": true}] ~~END~~ @@ -20,7 +20,7 @@ SELECT * FROM forjson_datatypes_vu_v_money GO ~~START~~ nvarchar -[{"amoney":3148.2900}] +[{"amoney": 3148.2900}] ~~END~~ @@ -28,7 +28,7 @@ SELECT * FROM forjson_datatypes_vu_v_smallmoney GO ~~START~~ nvarchar -[{"asmallmoney":3148.2900}] +[{"asmallmoney": 3148.2900}] ~~END~~ @@ -37,7 +37,7 @@ SELECT * FROM forjson_datatypes_vu_v_approx_numerics GO ~~START~~ nvarchar -[{"afloat":12.05,"areal":120.53}] +[{"afloat": 12.05, "areal": 120.53}] ~~END~~ @@ -46,7 +46,7 @@ SELECT * FROM forjson_datatypes_vu_v_time_date GO ~~START~~ nvarchar -[{"atime":"23:17:08.56","adate":"2022-11-11"}] +[{"atime": "23:17:08.56", "adate": "2022-11-11"}] ~~END~~ @@ -54,7 +54,7 @@ SELECT * FROM forjson_datatypes_vu_v_smalldatetime GO ~~START~~ nvarchar -[{"asmalldatetime":"2022-11-11T23:17:00"}] +[{"asmalldatetime": "2022-11-11T23:17:00"}] ~~END~~ @@ -62,7 +62,7 @@ SELECT * FROM forjson_datatypes_vu_v_datetime GO ~~START~~ nvarchar -[{"adatetime":"2022-11-11T23:17:08.56"}] +[{"adatetime": "2022-11-11T23:17:08.56"}] ~~END~~ @@ -70,7 +70,7 @@ SELECT * FROM forjson_datatypes_vu_v_datetime2 GO ~~START~~ nvarchar -[{"adatetime2":"2022-11-11T23:17:08.56"}] +[{"adatetime2": "2022-11-11T23:17:08.56"}] ~~END~~ @@ -78,7 +78,7 @@ SELECT * FROM forjson_datatypes_vu_v_datetimeoffset GO ~~START~~ nvarchar -[{"adatetimeoffset":"2022-11-11T23:17:08.56Z","adatetimeoffset_2":"2012-10-12T12:34:56+02:30"}] +[{"adatetimeoffset": "2022-11-11T23:17:08.56Z", "adatetimeoffset_2": "2012-10-12T12:34:56+02:30"}] ~~END~~ @@ -87,7 +87,7 @@ SELECT * FROM forjson_datatypes_vu_v_strings GO ~~START~~ nvarchar -[{"achar":"a","avarchar":"abc","atext":"abc"}] +[{"achar": "a", "avarchar": "abc", "atext": "abc"}] ~~END~~ @@ -96,6 +96,40 @@ SELECT * FROM forjson_datatypes_vu_v_unicode_strings GO ~~START~~ nvarchar -[{"anchar":"abc ","anvarchar":"abc","antext":"abc"}] +[{"anchar": "abc ", "anvarchar": "abc", "antext": "abc"}] +~~END~~ + + + +-- NULL datetime and datetimeoffset +SELECT * FROM forjson_datatypes_vu_v_nulldatetime +GO +~~START~~ +nvarchar +[{}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_nullsmalldatetime +GO +~~START~~ +nvarchar +[{}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_nulldatetime2 +GO +~~START~~ +nvarchar +[{}] +~~END~~ + + +SELECT * FROM forjson_datatypes_vu_v_nulldatetimeoffset +GO +~~START~~ +nvarchar +[{}] ~~END~~ diff --git a/test/JDBC/expected/forjson-nesting-vu-cleanup.out b/test/JDBC/expected/forjson-nesting-vu-cleanup.out new file mode 100644 index 0000000000..202343737b --- /dev/null +++ b/test/JDBC/expected/forjson-nesting-vu-cleanup.out @@ -0,0 +1,45 @@ +-- FOR JSON PATH CLAUSE with nested json support for existing objects +DROP VIEW forjson_nesting_vu_v_users +GO + +DROP VIEW forjson_nesting_vu_v_products +GO + +DROP VIEW forjson_nesting_vu_v_orders +GO + +-- FOR JSON PATH support for multiple layers of nested JSON objects +DROP VIEW forjson_nesting_vu_v_deep +GO + +-- FOR JSON PATH support for multiple layers of nested JSON objects w/ join +DROP VIEW forjson_nesting_vu_v_join_deep +GO + +-- FOR JSON PATH Support for key-values being inserted into mid layer of multi-layered JSON object +DROP VIEW forjson_nesting_vu_v_layered_insert +GO + +-- Error related to inserting value at Json object location +DROP VIEW forjson_nesting_vu_v_error +GO + +-- Queries that check NULL nested json object insert +DROP VIEW forjson_nesting_vu_v_no_null +GO + +DROP VIEW forjson_nesting_vu_v_with_null +GO + +-- DROP Tables +DROP TABLE forjson_nesting_vu_t_users +GO + +DROP TABLE forjson_nesting_vu_t_products +GO + +DROP TABLE forjson_nesting_vu_t_orders +GO + +DROP TABLE forjson_nesting_vu_t_null_users +GO diff --git a/test/JDBC/expected/forjson-nesting-vu-prepare.out b/test/JDBC/expected/forjson-nesting-vu-prepare.out new file mode 100644 index 0000000000..4f4f1ea1f3 --- /dev/null +++ b/test/JDBC/expected/forjson-nesting-vu-prepare.out @@ -0,0 +1,176 @@ +CREATE TABLE forjson_nesting_vu_t_users ( + [Id] int, + [firstname] varchar(50), + [lastname] varchar(50), + [email] varchar(50), +); +GO +CREATE TABLE forjson_nesting_vu_t_products ( + [Id] int, + [name] varchar(50), + [price] varchar (25) +); +GO +CREATE TABLE forjson_nesting_vu_t_orders ( + [Id] int, + [userid] int, + [productid] int, + [quantity] int, + [orderdate] Date +); +GO +CREATE TABLE forjson_nesting_vu_t_null_users ( + [Id] int, + [firstname] varchar(50), + [lastname] varchar(50), + [email] varchar(50), + [phone] varchar(25) +); +GO + +INSERT INTO forjson_nesting_vu_t_users +VALUES + (1, 'John', 'Doe', 'johndoe@gmail.com'), + (2, 'Jane', 'Smith', 'janesmith@yahoo.com'), + (3, 'Mike', 'Johnson', 'mikejohnson'); +GO +~~ROW COUNT: 3~~ + + +INSERT INTO forjson_nesting_vu_t_products +VALUES + (1, 'Product A', '10.99'), + (2, 'Product B', '19.99'), + (3, 'Product C', '5.99'); +GO +~~ROW COUNT: 3~~ + + +INSERT INTO forjson_nesting_vu_t_orders +VALUES + (1, 1, 1, 2, '2023-06-25'), + (2, 1, 2, 1, '2023-06-25'), + (3, 2, 3, 3, '2023-06-26'); +GO +~~ROW COUNT: 3~~ + + +INSERT INTO forjson_nesting_vu_t_null_users +VALUES + (1, 'John', 'Doe', 'johndoe@gmail.com', '123-456-7890'), + (2, 'Jane', 'Smith', 'janesmith@yahoo.com', NULL), + (3, NULL, NULL, 'mikejohnson@myspace.com', '098-765-4321'), + (4, 'Sergio', 'Giavanni', NULL, NULL); +GO +~~ROW COUNT: 4~~ + + +-- FOR JSON PATH CLAUSE with nested json support for existing objects +CREATE VIEW forjson_nesting_vu_v_users AS +SELECT ( + SELECT Id, + firstname AS "Name.first", + lastname AS "Name.last", + email + FROM forjson_nesting_vu_t_users + FOR JSON PATH +) c1 +GO + +CREATE VIEW forjson_nesting_vu_v_products AS +SELECT ( + SELECT Id, + name AS "Info.name", + price AS "Info.price" + FROM forjson_nesting_vu_t_products + FOR JSON PATH +) c1 +GO + +CREATE VIEW forjson_nesting_vu_v_orders AS +SELECT ( + SELECT Id AS "Id.orderid", + userid AS "Id.userid", + productid AS "Id.productid", + quantity AS "orderinfo.quantity", + orderdate AS "orderinfo.orderdate" + FROM forjson_nesting_vu_t_orders + FOR JSON PATH +) c1 +GO + +-- FOR JSON PATH support for multiple layers of nested JSON objects +CREATE VIEW forjson_nesting_vu_v_deep AS +SELECT ( + SELECT Id, + firstname AS "User.info.name.first", + lastname AS "User.info.name.last" + FROM forjson_nesting_vu_t_users + FOR JSON PATH +) c1 +GO + +-- FOR JSON PATH support for multiple layers of nested JSON objects w/ join +CREATE VIEW forjson_nesting_vu_v_join_deep AS +SELECT ( + SELECT U.Id "User.id", + O.quantity AS "User.order.info.quantity", + O.orderdate AS "User.order.info.orderdate" + FROM forjson_nesting_vu_t_users U + JOIN forjson_nesting_vu_t_orders O + ON (U.id = O.userid) + FOR JSON PATH +) c1 +GO + +-- FOR JSON PATH Support for key-values being inserted into mid layer of multi-layered JSON object +CREATE VIEW forjson_nesting_vu_v_layered_insert AS +SELECT ( + SELECT U.id, + O.id AS "Order.Orderid", + P.id AS "Order.Product.Productid", + O.orderdate AS "Order.date" + FROM forjson_nesting_vu_t_users U + JOIN forjson_nesting_vu_t_orders O + ON (U.id = O.userid) + JOIN forjson_nesting_vu_t_products P + ON (P.id = O.productid) + FOR JSON PATH +) c1 +GO + +-- Error related to inserting value at Json object location +CREATE VIEW forjson_nesting_vu_v_error AS +SELECT ( + SELECT id, + firstname AS "user.name", + lastname AS "user.name.last" + FROM forjson_nesting_vu_t_users + FOR JSON PATH +) +GO + +-- Queries that check NULL nested json object insert +CREATE VIEW forjson_nesting_vu_v_no_null AS +SELECT ( + SELECT id, + firstname AS "user.name.first", + lastname AS "user.name.last", + email AS "contact.email", + phone AS "contact.phone" + FROM forjson_nesting_vu_t_null_users + FOR JSON PATH +) +GO + +CREATE VIEW forjson_nesting_vu_v_with_null AS +SELECT ( + SELECT id, + firstname AS "user.name.first", + lastname AS "user.name.last", + email AS "contact.email", + phone AS "contact.phone" + FROM forjson_nesting_vu_t_null_users + FOR JSON PATH, INCLUDE_NULL_VALUES +) +GO diff --git a/test/JDBC/expected/forjson-nesting-vu-verify.out b/test/JDBC/expected/forjson-nesting-vu-verify.out new file mode 100644 index 0000000000..277e0bfb88 --- /dev/null +++ b/test/JDBC/expected/forjson-nesting-vu-verify.out @@ -0,0 +1,110 @@ +-- Display Table Contents +SELECT * FROM forjson_nesting_vu_t_users +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar +1#!#John#!#Doe#!#johndoe@gmail.com +2#!#Jane#!#Smith#!#janesmith@yahoo.com +3#!#Mike#!#Johnson#!#mikejohnson +~~END~~ + + +SELECT * FROM forjson_nesting_vu_t_products +GO +~~START~~ +int#!#varchar#!#varchar +1#!#Product A#!#10.99 +2#!#Product B#!#19.99 +3#!#Product C#!#5.99 +~~END~~ + + +SELECT * FROM forjson_nesting_vu_t_orders +GO +~~START~~ +int#!#int#!#int#!#int#!#date +1#!#1#!#1#!#2#!#2023-06-25 +2#!#1#!#2#!#1#!#2023-06-25 +3#!#2#!#3#!#3#!#2023-06-26 +~~END~~ + + +-- FOR JSON PATH CLAUSE with nested json support for existing objects +SELECT * FROM forjson_nesting_vu_v_users +GO +~~START~~ +nvarchar +[{"Id": 1, "Name": {"first": "John", "last": "Doe"}, "email": "johndoe@gmail.com"}, {"Id": 2, "Name": {"first": "Jane", "last": "Smith"}, "email": "janesmith@yahoo.com"}, {"Id": 3, "Name": {"first": "Mike", "last": "Johnson"}, "email": "mikejohnson"}] +~~END~~ + + +SELECT * FROM forjson_nesting_vu_v_products +GO +~~START~~ +nvarchar +[{"Id": 1, "Info": {"name": "Product A", "price": "10.99"}}, {"Id": 2, "Info": {"name": "Product B", "price": "19.99"}}, {"Id": 3, "Info": {"name": "Product C", "price": "5.99"}}] +~~END~~ + + +SELECT * FROM forjson_nesting_vu_v_orders +GO +~~START~~ +nvarchar +[{"Id": {"orderid": 1, "userid": 1, "productid": 1}, "orderinfo": {"quantity": 2, "orderdate": "2023-06-25"}}, {"Id": {"orderid": 2, "userid": 1, "productid": 2}, "orderinfo": {"quantity": 1, "orderdate": "2023-06-25"}}, {"Id": {"orderid": 3, "userid": 2, "productid": 3}, "orderinfo": {"quantity": 3, "orderdate": "2023-06-26"}}] +~~END~~ + + +-- FOR JSON PATH support for multiple layers of nested JSON objects +SELECT * FROM forjson_nesting_vu_v_deep +GO +~~START~~ +nvarchar +[{"Id": 1, "User": {"info": {"name": {"first": "John", "last": "Doe"}}}}, {"Id": 2, "User": {"info": {"name": {"first": "Jane", "last": "Smith"}}}}, {"Id": 3, "User": {"info": {"name": {"first": "Mike", "last": "Johnson"}}}}] +~~END~~ + + +-- FOR JSON PATH support for multiple layers of nested JSON objects w/ join +SELECT * FROM forjson_nesting_vu_v_join_deep +GO +~~START~~ +nvarchar +[{"User": {"id": 1, "order": {"info": {"quantity": 2, "orderdate": "2023-06-25"}}}}, {"User": {"id": 1, "order": {"info": {"quantity": 1, "orderdate": "2023-06-25"}}}}, {"User": {"id": 2, "order": {"info": {"quantity": 3, "orderdate": "2023-06-26"}}}}] +~~END~~ + + +-- FOR JSON PATH Support for key-values being inserted into mid layer of multi-layered JSON object +SELECT * FROM forjson_nesting_vu_v_layered_insert +GO +~~START~~ +nvarchar +[{"id": 1, "Order": {"Orderid": 1, "Product": {"Productid": 1}, "date": "2023-06-25"}}, {"id": 1, "Order": {"Orderid": 2, "Product": {"Productid": 2}, "date": "2023-06-25"}}, {"id": 2, "Order": {"Orderid": 3, "Product": {"Productid": 3}, "date": "2023-06-26"}}] +~~END~~ + + +-- Error related to inserting value at Json object location +SELECT * FROM forjson_nesting_vu_v_error +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Property user.name.last cannot be generated in JSON output due to a conflict with another column name or alias. Use different names and aliases for each column in SELECT list.)~~ + + +-- Queries that check NULL nested json object insert +SELECT * FROM forjson_nesting_vu_v_no_null +GO +~~START~~ +nvarchar +[{"id": 1, "user": {"name": {"first": "John", "last": "Doe"}}, "contact": {"email": "johndoe@gmail.com", "phone": "123-456-7890"}}, {"id": 2, "user": {"name": {"first": "Jane", "last": "Smith"}}, "contact": {"email": "janesmith@yahoo.com"}}, {"id": 3, "contact": {"email": "mikejohnson@myspace.com", "phone": "098-765-4321"}}, {"id": 4, "user": {"name": {"first": "Sergio", "last": "Giavanni"}}}] +~~END~~ + + +SELECT * FROM forjson_nesting_vu_v_with_null +GO +~~START~~ +nvarchar +[{"id": 1, "user": {"name": {"first": "John", "last": "Doe"}}, "contact": {"email": "johndoe@gmail.com", "phone": "123-456-7890"}}, {"id": 2, "user": {"name": {"first": "Jane", "last": "Smith"}}, "contact": {"email": "janesmith@yahoo.com", "phone": null}}, {"id": 3, "user": {"name": {"first": null, "last": null}}, "contact": {"email": "mikejohnson@myspace.com", "phone": "098-765-4321"}}, {"id": 4, "user": {"name": {"first": "Sergio", "last": "Giavanni"}}, "contact": {"email": null, "phone": null}}] +~~END~~ + + diff --git a/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-cleanup.out b/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-cleanup.out new file mode 100644 index 0000000000..8cb72c506f --- /dev/null +++ b/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-cleanup.out @@ -0,0 +1,59 @@ +-- FOR JSON AUTO clause not supported +DROP VIEW forjson_subquery_vu_v_auto +GO +~~ERROR (Code: 3701)~~ + +~~ERROR (Message: view "forjson_subquery_vu_v_auto" does not exist)~~ + + +-- Alias/colname is not present +DROP VIEW forjson_subquery_vu_v_no_alias +GO + +DROP VIEW forjson_subquery_vu_v_with +GO + +DROP VIEW forjson_subquery_vu_v_with_order_by +GO + +-- Binary strings +DROP VIEW forjson_subquery_vu_v_binary_strings +GO + +DROP VIEW forjson_subquery_vu_v_varbinary_strings +GO + +-- Rowversion and timestamp +DROP VIEW forjson_subquery_vu_v_rowversion +GO + +DROP VIEW forjson_subquery_vu_v_timestamp +GO + +-- BABEL-3569/BABEL-3690 return 0 rows for empty rowset +DROP PROCEDURE forjson_subquery_vu_p_empty +GO + +-- exercise tsql_select_for_json_result internal function +DROP VIEW forjson_subquery_vu_v_internal +GO + +DROP TABLE forjson_subquery_vu_t_countries +GO + +DROP TABLE forjson_subquery_vu_t1 +GO + +-- Binary strings +DROP TABLE forjson_subquery_vu_t_binary_strings +GO + +-- Rowversion and timestamp +DROP TABLE forjson_subquery_vu_t_rowversion +GO + +DROP TABLE forjson_subquery_vu_t_timestamp +GO + +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'strict'; +GO diff --git a/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-prepare.out b/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-prepare.out new file mode 100644 index 0000000000..47f572490d --- /dev/null +++ b/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-prepare.out @@ -0,0 +1,151 @@ + +-- 14.7 (aka extension version 2.4.0) has a major change to how FOR JSON +-- has been implemented, which slightly changes the behavior around some old error +-- messages as well, so we need to move those tests to a new test file that separately +-- exercises them outside of the pre-14.6 upgrade tests. +CREATE TABLE forjson_subquery_vu_t_countries ( +[Id] INT, +[Age] INT, +[Country] VARCHAR(25)) +GO + +INSERT INTO forjson_subquery_vu_t_countries values +(1,25, 'India'), +(2,40, 'USA'), +(3,30, 'India'), +(4,20, NULL), +(5,10, 'USA') +GO +~~ROW COUNT: 5~~ + + +create table forjson_subquery_vu_t1 (x int) +insert into forjson_subquery_vu_t1 values (1) +go +~~ROW COUNT: 1~~ + + +-- FOR JSON AUTO clause not supported +CREATE VIEW forjson_subquery_vu_v_auto AS +SELECT ( + SELECT Id, + State + FROM forjson_subquery_vu_t1 + FOR JSON AUTO +) c1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "id" does not exist)~~ + + +-- Alias/colname not present +CREATE VIEW forjson_subquery_vu_v_no_alias AS +SELECT ( + SELECT 2 + FOR JSON PATH +) c1 +GO + +CREATE VIEW forjson_subquery_vu_v_with AS +WITH forjson_subquery_vu_with1(avg_age) AS ( + SELECT avg(Age) + FROM forjson_subquery_vu_t_countries +) +SELECT ( + SELECT Id, Age, Country + FROM forjson_subquery_vu_t_countries, forjson_subquery_vu_with1 + WHERE Age >= forjson_subquery_vu_with1.avg_age + FOR JSON PATH +) C1 +GO + +CREATE VIEW forjson_subquery_vu_v_with_order_by AS +WITH forjson_subquery_vu_with2(avg_age) AS ( + SELECT avg(Age) + FROM forjson_subquery_vu_t_countries +) +SELECT ( + SELECT Id, Age, Country + FROM forjson_subquery_vu_t_countries, forjson_subquery_vu_with2 + WHERE Age >= forjson_subquery_vu_with2.avg_age + ORDER BY Country + FOR JSON PATH +) c1 +GO + +-- Binary strings +CREATE TABLE forjson_subquery_vu_t_binary_strings(abinary binary, avarbinary varbinary(10)) +GO +INSERT forjson_subquery_vu_t_binary_strings VALUES (123456,0x0a0b0c0d0e) +GO +~~ROW COUNT: 1~~ + + +-- Rowversion and timestamp +EXEC sp_babelfish_configure 'babelfishpg_tsql.escape_hatch_rowversion', 'ignore'; +GO + +CREATE TABLE forjson_subquery_vu_t_rowversion (myKey int, myValue int,RV rowversion); +GO +INSERT INTO forjson_subquery_vu_t_rowversion (myKey, myValue) VALUES (1, 0); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE forjson_subquery_vu_t_timestamp (myKey int, myValue int, timestamp); +GO +INSERT INTO forjson_subquery_vu_t_timestamp (myKey, myValue) VALUES (1, 0); +GO +~~ROW COUNT: 1~~ + + +-- Binary strings +CREATE VIEW forjson_subquery_vu_v_binary_strings AS +SELECT +( + SELECT abinary + FROM forjson_subquery_vu_t_binary_strings + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_subquery_vu_v_varbinary_strings AS +SELECT +( + SELECT avarbinary + FROM forjson_subquery_vu_t_binary_strings + FOR JSON PATH +) as c1; +GO + +-- Rowversion and timestamp +CREATE VIEW forjson_subquery_vu_v_rowversion AS +SELECT +( + SELECT * + FROM forjson_subquery_vu_t_rowversion + FOR JSON PATH +) as c1; +GO + +CREATE VIEW forjson_subquery_vu_v_timestamp AS +SELECT +( + SELECT * + FROM forjson_subquery_vu_t_timestamp + FOR JSON PATH +) as c1; +GO + +-- BABEL-3569/BABEL-3690 return 0 rows for empty rowset +CREATE PROCEDURE forjson_subquery_vu_p_empty AS +SELECT * FROM forjson_subquery_vu_t_countries + WHERE 1 = 0 + FOR JSON PATH +GO + +-- exercise tsql_select_for_json_result internal function +CREATE VIEW forjson_subquery_vu_v_internal AS +SELECT * FROM tsql_select_for_json_result('abcd') +GO diff --git a/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-verify.out b/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-verify.out new file mode 100644 index 0000000000..c4553b14cd --- /dev/null +++ b/test/JDBC/expected/forjson-subquery-before-14_10-or-15_5-vu-verify.out @@ -0,0 +1,95 @@ +-- FOR JSON AUTO clause not supported +SELECT * FROM forjson_subquery_vu_v_auto +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "forjson_subquery_vu_v_auto" does not exist)~~ + + +-- Alias/colname is not present +SELECT * FROM forjson_subquery_vu_v_no_alias +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 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)~~ + + +SELECT * FROM forjson_subquery_vu_v_with +GO +~~START~~ +nvarchar +[{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"}] +~~END~~ + + +SELECT * FROM forjson_subquery_vu_v_with_order_by +GO +~~START~~ +nvarchar +[{"Id":1,"Age":25,"Country":"India"},{"Id":3,"Age":30,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"}] +~~END~~ + + +-- Binary strings +SELECT * FROM forjson_subquery_vu_v_binary_strings +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: binary types are not supported with FOR JSON)~~ + + +SELECT * FROM forjson_subquery_vu_v_varbinary_strings +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: binary types are not supported with FOR JSON)~~ + + +-- Rowversion and timestamp +SELECT * FROM forjson_subquery_vu_v_rowversion +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: binary types are not supported with FOR JSON)~~ + + +SELECT * FROM forjson_subquery_vu_v_timestamp +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: binary types are not supported with FOR JSON)~~ + + +-- BABEL-3569/BABEL-3690 return 0 rows for empty rowset +EXEC forjson_subquery_vu_p_empty +GO +~~START~~ +nvarchar +~~END~~ + + +SELECT @@rowcount +GO +~~START~~ +int +0 +~~END~~ + + +-- exercise tsql_select_for_json_result internal function +SELECT * FROM forjson_subquery_vu_v_internal +GO +~~START~~ +nvarchar +abcd +~~END~~ diff --git a/test/JDBC/expected/forjson-subquery-vu-verify.out b/test/JDBC/expected/forjson-subquery-vu-verify.out index 89f76f3dd5..e9e82cce6c 100644 --- a/test/JDBC/expected/forjson-subquery-vu-verify.out +++ b/test/JDBC/expected/forjson-subquery-vu-verify.out @@ -20,7 +20,7 @@ SELECT * FROM forjson_subquery_vu_v_with GO ~~START~~ nvarchar -[{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"}] +[{"Id": 1, "Age": 25, "Country": "India"}, {"Id": 2, "Age": 40, "Country": "USA"}, {"Id": 3, "Age": 30, "Country": "India"}] ~~END~~ @@ -28,7 +28,7 @@ SELECT * FROM forjson_subquery_vu_v_with_order_by GO ~~START~~ nvarchar -[{"Id":1,"Age":25,"Country":"India"},{"Id":3,"Age":30,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"}] +[{"Id": 1, "Age": 25, "Country": "India"}, {"Id": 3, "Age": 30, "Country": "India"}, {"Id": 2, "Age": 40, "Country": "USA"}] ~~END~~ diff --git a/test/JDBC/expected/forjson-vu-verify.out b/test/JDBC/expected/forjson-vu-verify.out index 4f8a705dba..ce8d2391eb 100644 --- a/test/JDBC/expected/forjson-vu-verify.out +++ b/test/JDBC/expected/forjson-vu-verify.out @@ -32,12 +32,12 @@ int#!#varchar ~~END~~ --- FOR JSON PATH clause without nested support +-- FOR JSON PATH clause with nested support SELECT * FROM forjson_vu_v_people GO ~~START~~ nvarchar -[{"EmpId":1,"Name.FirstName":"Divya","Name.LastName":"Kumar"},{"EmpId":2,"Name.LastName":"Khanna","State":"Bengaluru"},{"EmpId":3,"Name.FirstName":"Tom","Name.LastName":"Mehta","State":"Kolkata"},{"EmpId":4,"Name.FirstName":"Kane","State":"Delhi"}] +[{"EmpId": 1, "Name": {"FirstName": "Divya", "LastName": "Kumar"}}, {"EmpId": 2, "Name": {"LastName": "Khanna"}, "State": "Bengaluru"}, {"EmpId": 3, "Name": {"FirstName": "Tom", "LastName": "Mehta"}, "State": "Kolkata"}, {"EmpId": 4, "Name": {"FirstName": "Kane"}, "State": "Delhi"}] ~~END~~ @@ -45,16 +45,16 @@ SELECT * FROM forjson_vu_v_countries GO ~~START~~ nvarchar -[{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"},{"Id":4,"Age":20},{"Id":5,"Age":10,"Country":"USA"}] +[{"Id": 1, "Age": 25, "Country": "India"}, {"Id": 2, "Age": 40, "Country": "USA"}, {"Id": 3, "Age": 30, "Country": "India"}, {"Id": 4, "Age": 20}, {"Id": 5, "Age": 10, "Country": "USA"}] ~~END~~ --- Multiple tables without nested support +-- Multiple tables with nested support SELECT * FROM forjson_vu_v_join GO ~~START~~ nvarchar -[{"Person.Name":"Divya","Person.Surname":"Kumar","Employee.Price":25,"Employee.Quantity":"India"},{"Person.Surname":"Khanna","Employee.Price":40,"Employee.Quantity":"USA"},{"Person.Name":"Tom","Person.Surname":"Mehta","Employee.Price":30,"Employee.Quantity":"India"},{"Person.Name":"Kane","Employee.Price":20}] +[{"Person": {"Name": "Divya", "Surname": "Kumar"}, "Employee": {"Price": 25, "Quantity": "India"}}, {"Person": {"Surname": "Khanna"}, "Employee": {"Price": 40, "Quantity": "USA"}}, {"Person": {"Name": "Tom", "Surname": "Mehta"}, "Employee": {"Price": 30, "Quantity": "India"}}, {"Person": {"Name": "Kane"}, "Employee": {"Price": 20}}] ~~END~~ @@ -63,7 +63,7 @@ SELECT * FROM forjson_vu_v_root GO ~~START~~ nvarchar -{"root":[{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"}]} +{"root": [{"FirstName": "Divya", "LastName": "Kumar"}, {"LastName": "Khanna"}, {"FirstName": "Tom", "LastName": "Mehta"}, {"FirstName": "Kane"}]} ~~END~~ @@ -72,7 +72,7 @@ SELECT * FROM forjson_vu_v_root_value GO ~~START~~ nvarchar -{"Employee":[{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"}]} +{"Employee": [{"FirstName": "Divya", "LastName": "Kumar"}, {"LastName": "Khanna"}, {"FirstName": "Tom", "LastName": "Mehta"}, {"FirstName": "Kane"}]} ~~END~~ @@ -81,7 +81,7 @@ SELECT * FROM forjson_vu_v_empty_root GO ~~START~~ nvarchar -{"":[{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"}]} +{"": [{"FirstName": "Divya", "LastName": "Kumar"}, {"LastName": "Khanna"}, {"FirstName": "Tom", "LastName": "Mehta"}, {"FirstName": "Kane"}]} ~~END~~ @@ -90,7 +90,7 @@ SELECT * FROM forjson_vu_v_without_array_wrapper GO ~~START~~ nvarchar -{"FirstName":"Divya","LastName":"Kumar"},{"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane"} +{"FirstName": "Divya", "LastName": "Kumar"}, {"LastName": "Khanna"}, {"FirstName": "Tom", "LastName": "Mehta"}, {"FirstName": "Kane"} ~~END~~ @@ -99,7 +99,7 @@ SELECT * FROM forjson_vu_v_include_null_values GO ~~START~~ nvarchar -[{"FirstName":"Divya","LastName":"Kumar"},{"FirstName":null,"LastName":"Khanna"},{"FirstName":"Tom","LastName":"Mehta"},{"FirstName":"Kane","LastName":null}] +[{"FirstName": "Divya", "LastName": "Kumar"}, {"FirstName": null, "LastName": "Khanna"}, {"FirstName": "Tom", "LastName": "Mehta"}, {"FirstName": "Kane", "LastName": null}] ~~END~~ @@ -108,7 +108,7 @@ SELECT * FROM forjson_vu_v_root_include_null_values GO ~~START~~ nvarchar -{"Employee":[{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"},{"Id":4,"Age":20,"Country":null},{"Id":5,"Age":10,"Country":"USA"}]} +{"Employee": [{"Id": 1, "Age": 25, "Country": "India"}, {"Id": 2, "Age": 40, "Country": "USA"}, {"Id": 3, "Age": 30, "Country": "India"}, {"Id": 4, "Age": 20, "Country": null}, {"Id": 5, "Age": 10, "Country": "USA"}]} ~~END~~ @@ -116,7 +116,7 @@ SELECT * FROM forjson_vu_v_without_array_wrapper_include_null_values GO ~~START~~ nvarchar -{"Id":1,"Age":25,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"},{"Id":3,"Age":30,"Country":"India"},{"Id":4,"Age":20,"Country":null},{"Id":5,"Age":10,"Country":"USA"} +{"Id": 1, "Age": 25, "Country": "India"}, {"Id": 2, "Age": 40, "Country": "USA"}, {"Id": 3, "Age": 30, "Country": "India"}, {"Id": 4, "Age": 20, "Country": null}, {"Id": 5, "Age": 10, "Country": "USA"} ~~END~~ @@ -126,7 +126,7 @@ EXECUTE forjson_vu_p_params1 @id = 2 GO ~~START~~ nvarchar -[{"State":"Bengaluru"}] +[{"State": "Bengaluru"}] ~~END~~ @@ -134,7 +134,7 @@ EXECUTE forjson_vu_p_params2 @id = 3 GO ~~START~~ nvarchar -[{"nam\"@e":"Tom","State\"@":"Kolkata"}] +[{"nam\"@e": "Tom", "State\"@": "Kolkata"}] ~~END~~ @@ -143,7 +143,7 @@ SELECT * FROM forjson_vu_v_nulls GO ~~START~~ nvarchar -[{},{},{}] +[{}, {}, {}] ~~END~~ @@ -152,6 +152,6 @@ SELECT * FROM forjson_vu_v_order_by GO ~~START~~ nvarchar -[{"Id":5,"Age":10,"Country":"USA"},{"Id":4,"Age":20},{"Id":1,"Age":25,"Country":"India"},{"Id":3,"Age":30,"Country":"India"},{"Id":2,"Age":40,"Country":"USA"}] +[{"Id": 5, "Age": 10, "Country": "USA"}, {"Id": 4, "Age": 20}, {"Id": 1, "Age": 25, "Country": "India"}, {"Id": 3, "Age": 30, "Country": "India"}, {"Id": 2, "Age": 40, "Country": "USA"}] ~~END~~ diff --git a/test/JDBC/expected/format-dep-vu-cleanup.out b/test/JDBC/expected/format-dep-vu-cleanup.out new file mode 100644 index 0000000000..858400af1b --- /dev/null +++ b/test/JDBC/expected/format-dep-vu-cleanup.out @@ -0,0 +1,188 @@ +-- date +drop view format_dep_view_date +go + +drop procedure format_dep_proc_date +GO + +drop function format_dep_func_date() +go + +-- datetime +drop view format_dep_view_datetime +go + +drop procedure format_dep_proc_datetime +GO + +drop function format_dep_func_datetime() +go + +-- datetime2 +drop view format_dep_view_datetime2 +go + +drop procedure format_dep_proc_datetime2 +GO + +drop function format_dep_func_datetime2() +go + +-- smalldatetime +drop view format_dep_view_smalldatetime +go + +drop procedure format_dep_proc_smalldatetime +GO + +drop function format_dep_func_smalldatetime() +go + +-- time +drop view format_dep_view_time +go + +drop view format_datetime_dep_view_time +go + +drop view format_datetime_dep_view_time2 +go + +drop procedure format_dep_proc_time +GO + +drop function format_dep_func_time() +go + +-- tinyint +drop view format_dep_view_tinyint +go + +drop procedure format_dep_proc_tinyint +GO + +-- smallint +drop view format_dep_view_smallint +go + +drop procedure format_dep_proc_smallint +GO + +-- int +drop view format_dep_view_int +go + +drop view format_numeric_dep_view_int +go + +drop procedure format_dep_proc_int +GO + +-- bigint +drop view format_dep_view_bigint +go + +drop procedure format_dep_proc_bigint +GO + +-- decimal +drop view format_dep_view_decimal +go + +drop procedure format_dep_proc_decimal +GO + +-- numeric +drop view format_dep_view_numeric +go + +drop procedure format_dep_proc_numeric +GO + +-- real +drop view format_dep_view_real +go + +drop procedure format_dep_proc_real +GO + +-- float +drop view format_dep_view_float +go + +drop procedure format_dep_proc_float +GO + +-- smallmoney +drop view format_dep_view_smallmoney +go + +drop procedure format_dep_proc_smallmoney +GO + +-- money +drop view format_dep_view_money +go + +drop procedure format_dep_proc_money +GO + +-- real +drop view format_dep_view_real2 +go + +drop procedure format_dep_proc_real2 +GO + +-- float +drop view format_dep_view_float2 +go + +drop procedure format_dep_proc_float2 +GO + +drop table format_dep_real_testing2; +GO +drop table format_dep_float_testing2; +GO + +drop table format_dep_smallint_testing; +GO + +drop table format_dep_tinyint_testing; +GO + +drop table format_dep_int_testing; +GO + +drop table format_dep_bigint_testing; +GO + +drop table format_dep_decimal_testing; +GO + +drop table format_dep_numeric_testing; +GO + +drop table format_dep_real_testing; +GO + +drop table format_dep_float_testing; +GO + +drop table format_dep_smallmoney_testing; +GO + +drop table format_dep_money_testing; +GO + +drop table format_dep_date_testing; +go +drop table format_dep_datetime_testing; +go +drop table format_dep_datetime2_testing; +go +drop table format_dep_smalldatetime_testing; +go +drop table format_dep_time_testing; +go diff --git a/test/JDBC/expected/format-dep-vu-prepare.out b/test/JDBC/expected/format-dep-vu-prepare.out new file mode 100644 index 0000000000..4314c528e7 --- /dev/null +++ b/test/JDBC/expected/format-dep-vu-prepare.out @@ -0,0 +1,561 @@ +CREATE TABLE format_dep_date_testing(d DATE); +INSERT INTO format_dep_date_testing VALUES('1753-1-1'); +INSERT INTO format_dep_date_testing VALUES('9999-12-31'); +INSERT INTO format_dep_date_testing VALUES('1992-05-23'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create table format_dep_datetime_testing ( dt DATETIME ); +INSERT INTO format_dep_datetime_testing VALUES('1753-1-1 00:00:00.000'); +INSERT INTO format_dep_datetime_testing VALUES('9999-12-31 23:59:59.456'); +INSERT INTO format_dep_datetime_testing VALUES('1992-05-23 23:40:30.000'); +INSERT INTO format_dep_datetime_testing VALUES('1999-12-31 23:59:59.123'); +INSERT INTO format_dep_datetime_testing VALUES('23:40:29.456'); +INSERT INTO format_dep_datetime_testing VALUES('23:40:30.000'); +INSERT INTO format_dep_datetime_testing VALUES('2020-03-14'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +create table format_dep_datetime2_testing ( dt2 DATETIME2 ); +INSERT INTO format_dep_datetime2_testing VALUES('0001-1-1 00:00:00'); +INSERT INTO format_dep_datetime2_testing VALUES('9999-12-31 23:59:59'); +INSERT INTO format_dep_datetime2_testing VALUES('1992-05-23 23:40:29'); +INSERT INTO format_dep_datetime2_testing VALUES('1992-05-23 23:40:30'); +INSERT INTO format_dep_datetime2_testing VALUES('1999-12-31 23:59:59'); +INSERT INTO format_dep_datetime2_testing VALUES('1999-12-31 23:59:59'); +INSERT INTO format_dep_datetime2_testing VALUES('23:40:29.236'); +INSERT INTO format_dep_datetime2_testing VALUES('23:40:30.000'); +INSERT INTO format_dep_datetime2_testing VALUES('2020-03-14'); +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~~ + + +create table format_dep_time_testing ( ti TIME ); +INSERT INTO format_dep_time_testing VALUES('00:00:00.12345'); +INSERT INTO format_dep_time_testing VALUES('3:53:59'); +INSERT INTO format_dep_time_testing VALUES('15:5:45.0000'); +INSERT INTO format_dep_time_testing VALUES('23:59:59.12345'); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_tinyint_testing(ti TINYINT); +INSERT INTO format_dep_tinyint_testing VALUES(0); +INSERT INTO format_dep_tinyint_testing VALUES(31); +INSERT INTO format_dep_tinyint_testing VALUES(255); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_smallint_testing(si SMALLINT); +INSERT INTO format_dep_smallint_testing VALUES(-2456); +INSERT INTO format_dep_smallint_testing VALUES(-62); +INSERT INTO format_dep_smallint_testing VALUES(282); +INSERT INTO format_dep_smallint_testing VALUES(2456); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_int_testing(it INT); +INSERT INTO format_dep_int_testing VALUES(-2147483); +INSERT INTO format_dep_int_testing VALUES(-586); +INSERT INTO format_dep_int_testing VALUES(7869); +INSERT INTO format_dep_int_testing VALUES(2147483); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_bigint_testing(bi BIGINT); +INSERT INTO format_dep_bigint_testing VALUES(-9223372036854); +INSERT INTO format_dep_bigint_testing VALUES(-352); +INSERT INTO format_dep_bigint_testing VALUES(2822); +INSERT INTO format_dep_bigint_testing VALUES(9223372036854); +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_real_testing(rt REAL); +INSERT INTO format_dep_real_testing VALUES(-3.40E+38); +INSERT INTO format_dep_real_testing VALUES(-3.312346E+38); +INSERT INTO format_dep_real_testing VALUES(-3.312341234E+38); +INSERT INTO format_dep_real_testing VALUES(-22.1234); +INSERT INTO format_dep_real_testing VALUES(22.1234); +INSERT INTO format_dep_real_testing VALUES(22.12341234); +INSERT INTO format_dep_real_testing VALUES(3.312346E+38); +INSERT INTO format_dep_real_testing VALUES(3.4E+38); +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~~ + + +CREATE TABLE format_dep_float_testing(ft FLOAT); +GO +INSERT INTO format_dep_float_testing VALUES(-1.79E+308); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing VALUES(-3.4E+38); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing VALUES(35.3675); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing VALUES(3.4E+38); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing VALUES(1.79E+308); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_smallmoney_testing(sm MONEY); +GO +INSERT INTO format_dep_smallmoney_testing VALUES(-214478.3648); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_smallmoney_testing VALUES(435627.1435); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_smallmoney_testing VALUES(-435627.1435); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_smallmoney_testing VALUES(214478.3647); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_money_testing(mt MONEY); +GO +INSERT INTO format_dep_money_testing VALUES(-92233720.5808); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_money_testing VALUES(-214478.3648); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_money_testing VALUES(435627.1435); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_money_testing VALUES(214478.3647); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_money_testing VALUES(92233720.5807); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_real_testing2(rt REAL); +GO +INSERT INTO format_dep_real_testing2 VALUES(-3.4E+1); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_real_testing2 VALUES(-34); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_real_testing2 VALUES(-3.312346789E+38); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_real_testing2 VALUES(22.1234565656565E+3); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_real_testing2 VALUES(22.1234123412341234); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_real_testing2 VALUES(3.312346E+38); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_real_testing2 VALUES(3.40E+38); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_float_testing2(ft FLOAT); +GO +INSERT INTO format_dep_float_testing2 VALUES(-3.312346789123456789E+38); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.3123489656565789); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.3123489656565); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.31234896565651); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.312348965656512); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.3123489656565123); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(33123489656565123.34); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.312348965656512345); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(3.3123489656565123456); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_float_testing2 VALUES(351234567891025621.1); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_decimal_testing(dt DECIMAL(15, 5)); +GO +INSERT INTO format_dep_decimal_testing VALUES(-8999999999.09909); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_decimal_testing VALUES(-352); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_decimal_testing VALUES(5478); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_decimal_testing VALUES(8999999999.99999); +GO +~~ROW COUNT: 1~~ + + +create table format_dep_smalldatetime_testing ( sdt smalldatetime ); +GO +INSERT INTO format_dep_smalldatetime_testing VALUES('1990-05-23 23:40:29'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_smalldatetime_testing VALUES('2022-12-31 23:59:59'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_smalldatetime_testing VALUES('2079-06-06 22:59:59'); +GO +~~ROW COUNT: 1~~ + + +CREATE TABLE format_dep_numeric_testing(nt NUMERIC(15, 4)); +GO +INSERT INTO format_dep_numeric_testing VALUES(-8999999999.0990); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_numeric_testing VALUES(-352); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_numeric_testing VALUES(5478); +GO +~~ROW COUNT: 1~~ + +INSERT INTO format_dep_numeric_testing VALUES(8999999999.9999); +GO +~~ROW COUNT: 1~~ + + +-- date +CREATE VIEW format_dep_view_date AS +select FORMAT(d, 'F','en-us') from format_dep_date_testing; +GO + +CREATE PROC format_dep_proc_date AS +select FORMAT(d, 'D','en-us') from format_dep_date_testing; +GO + +CREATE FUNCTION format_dep_func_date() +RETURNS date +AS +BEGIN +RETURN (select TOP 1 FORMAT(d, 'G','en-us') from format_dep_date_testing); +END +GO + +-- datetime +CREATE VIEW format_dep_view_datetime AS +select FORMAT(dt, 'd','en-us') from format_dep_datetime_testing; +GO + +CREATE PROC format_dep_proc_datetime AS +select FORMAT(dt, 'D','en-us') from format_dep_datetime_testing; +GO + +CREATE FUNCTION format_dep_func_datetime() +RETURNS datetime +AS +BEGIN +RETURN (select TOP 1 FORMAT(dt, 'f','en-us') from format_dep_datetime_testing); +END +GO + +-- datetime2 +CREATE VIEW format_dep_view_datetime2 AS +select FORMAT(dt2, 'F','en-us') from format_dep_datetime2_testing; +GO + +CREATE PROC format_dep_proc_datetime2 AS +select FORMAT(dt2, 'D','en-us') from format_dep_datetime2_testing; +GO + +CREATE FUNCTION format_dep_func_datetime2() +RETURNS datetime2 +AS +BEGIN +RETURN (select TOP 1 FORMAT(dt2, 'G','en-us') from format_dep_datetime2_testing); +END +GO + +-- smalldatetime +CREATE VIEW format_dep_view_smalldatetime AS +select FORMAT(sdt, 'F','en-us') from format_dep_smalldatetime_testing; +GO + +CREATE PROC format_dep_proc_smalldatetime AS +select FORMAT(sdt, 'f','en-us') from format_dep_smalldatetime_testing; +GO + +CREATE FUNCTION format_dep_func_smalldatetime() +RETURNS smalldatetime +AS +BEGIN +RETURN (select TOP 1 FORMAT(sdt, 'D','en-us') from format_dep_smalldatetime_testing); +END +GO + +-- time +CREATE VIEW format_dep_view_time AS +select FORMAT(ti, 'f','en-us') from format_dep_time_testing; +GO + +CREATE VIEW format_datetime_dep_view_time AS +select format_datetime(ti, 'd','en-us', 'time') from format_dep_time_testing; +GO + +CREATE VIEW format_datetime_dep_view_time2 AS +select format_datetime(ti, 'c','en-us', 'time') from format_dep_time_testing; +GO + +CREATE PROC format_dep_proc_time AS +select FORMAT(ti, 'D','en-us') from format_dep_time_testing; +GO + +CREATE FUNCTION format_dep_func_time() +RETURNS time +AS +BEGIN +RETURN (select TOP 1 FORMAT(ti, 'c','en-us') from format_dep_time_testing); +END +GO + +-- tinyint +CREATE VIEW format_dep_view_tinyint AS +SELECT FORMAT(ti, 'C0', 'en-us') from format_dep_tinyint_testing; +GO + +CREATE PROC format_dep_proc_tinyint AS +SELECT FORMAT(ti, 'C', 'en-us') from format_dep_tinyint_testing; +GO + +-- smallint +CREATE VIEW format_dep_view_smallint AS +SELECT FORMAT(si, 'C6', 'en-us') from format_dep_smallint_testing; +GO + +CREATE PROC format_dep_proc_smallint AS +SELECT FORMAT(si, 'C', 'aa-DJ') from format_dep_smallint_testing; +GO + +-- int +CREATE VIEW format_dep_view_int AS +SELECT FORMAT(it, 'C6', 'en-us') from format_dep_int_testing; +GO + +CREATE VIEW format_numeric_dep_view_int AS +SELECT format_numeric(it, 'C6', 'en-us', 'integer') from format_dep_int_testing; +GO + +CREATE PROC format_dep_proc_int AS +SELECT FORMAT(it, 'C', 'en-us') from format_dep_int_testing; +GO + +-- bigint +CREATE VIEW format_dep_view_bigint AS +SELECT FORMAT(bi, 'C6', 'en-us') from format_dep_bigint_testing; +GO + +CREATE PROC format_dep_proc_bigint AS +SELECT FORMAT(bi, 'C', 'en-us') from format_dep_bigint_testing; +GO + +-- decimal +CREATE VIEW format_dep_view_decimal AS +SELECT FORMAT(dt, 'C6', 'en-us') from format_dep_decimal_testing; +GO + +CREATE PROC format_dep_proc_decimal AS +SELECT FORMAT(dt, 'C', 'en-us') from format_dep_decimal_testing; +GO + +-- numeric +CREATE VIEW format_dep_view_numeric AS +SELECT FORMAT(nt, 'C6', 'en-us') from format_dep_numeric_testing; +GO + +CREATE PROC format_dep_proc_numeric AS +SELECT FORMAT(nt, 'C', 'en-us') from format_dep_numeric_testing; +GO + +-- real +CREATE VIEW format_dep_view_real AS +SELECT FORMAT(rt, 'C9', 'en-us') from format_dep_real_testing; +GO + +CREATE PROC format_dep_proc_real AS +SELECT FORMAT(rt, 'C', 'en-us') from format_dep_real_testing; +GO + +-- float +CREATE VIEW format_dep_view_float AS +SELECT FORMAT(ft, 'C9', 'en-us') from format_dep_float_testing; +GO + +CREATE PROC format_dep_proc_float AS +SELECT FORMAT(ft, 'C', 'en-us') from format_dep_float_testing; +GO + +-- smallmoney +CREATE VIEW format_dep_view_smallmoney AS +SELECT FORMAT(sm, 'C9', 'en-us') from format_dep_smallmoney_testing; +GO + +CREATE PROC format_dep_proc_smallmoney AS +SELECT FORMAT(sm, 'C', 'en-us') from format_dep_smallmoney_testing; +GO + +-- money +CREATE VIEW format_dep_view_money AS +SELECT FORMAT(mt, 'C9', 'en-us') from format_dep_money_testing; +GO + +CREATE PROC format_dep_proc_money AS +SELECT FORMAT(mt, 'C', 'en-us') from format_dep_money_testing; +GO + +-- real +CREATE VIEW format_dep_view_real2 AS +SELECT FORMAT(rt, 'C9', 'en-us') from format_dep_real_testing2; +GO + +CREATE PROC format_dep_proc_real2 AS +SELECT FORMAT(rt, 'C', 'en-us') from format_dep_real_testing2; +GO + +-- float +CREATE VIEW format_dep_view_float2 AS +SELECT FORMAT(ft, 'C9', 'en-us') from format_dep_float_testing2; +GO + +CREATE PROC format_dep_proc_float2 AS +SELECT FORMAT(ft, 'C', 'en-us') from format_dep_float_testing2; +GO diff --git a/test/JDBC/expected/format-dep-vu-verify.out b/test/JDBC/expected/format-dep-vu-verify.out new file mode 100644 index 0000000000..a0f6caa264 --- /dev/null +++ b/test/JDBC/expected/format-dep-vu-verify.out @@ -0,0 +1,501 @@ +-- date +select * from format_dep_view_date +go +~~START~~ +nvarchar +Monday, January 1, 1753 12:00:00 AM +Friday, December 31, 9999 12:00:00 AM +Saturday, May 23, 1992 12:00:00 AM +~~END~~ + + +exec format_dep_proc_date +GO +~~START~~ +nvarchar +Monday, January 1, 1753 +Friday, December 31, 9999 +Saturday, May 23, 1992 +~~END~~ + + +select * from format_dep_func_date() +go +~~START~~ +date +1753-01-01 +~~END~~ + + +-- datetime +select * from format_dep_view_datetime +go +~~START~~ +nvarchar +1/1/1753 +12/31/9999 +5/23/1992 +12/31/1999 +1/1/1900 +1/1/1900 +3/14/2020 +~~END~~ + + +exec format_dep_proc_datetime +GO +~~START~~ +nvarchar +Monday, January 1, 1753 +Friday, December 31, 9999 +Saturday, May 23, 1992 +Friday, December 31, 1999 +Monday, January 1, 1900 +Monday, January 1, 1900 +Saturday, March 14, 2020 +~~END~~ + + +select * from format_dep_func_datetime() +go +~~START~~ +datetime +1753-01-01 00:00:00.0 +~~END~~ + + +-- datetime2 +select * from format_dep_view_datetime2 +go +~~START~~ +nvarchar +Monday, January 1, 0001 12:00:00 AM +Friday, December 31, 9999 11:59:59 PM +Saturday, May 23, 1992 11:40:29 PM +Saturday, May 23, 1992 11:40:30 PM +Friday, December 31, 1999 11:59:59 PM +Friday, December 31, 1999 11:59:59 PM +Monday, January 1, 1900 11:40:29 PM +Monday, January 1, 1900 11:40:30 PM +Saturday, March 14, 2020 12:00:00 AM +~~END~~ + + +exec format_dep_proc_datetime2 +GO +~~START~~ +nvarchar +Monday, January 1, 0001 +Friday, December 31, 9999 +Saturday, May 23, 1992 +Saturday, May 23, 1992 +Friday, December 31, 1999 +Friday, December 31, 1999 +Monday, January 1, 1900 +Monday, January 1, 1900 +Saturday, March 14, 2020 +~~END~~ + + +select * from format_dep_func_datetime2() +go +~~START~~ +datetime2 +0001-01-01 00:00:00.0000000 +~~END~~ + + +-- smalldatetime +select * from format_dep_view_smalldatetime +go +~~START~~ +nvarchar +Wednesday, May 23, 1990 11:40:00 PM +Sunday, January 1, 2023 12:00:00 AM +Tuesday, June 6, 2079 11:00:00 PM +~~END~~ + + +exec format_dep_proc_smalldatetime +GO +~~START~~ +nvarchar +Wednesday, May 23, 1990 11:40 PM +Sunday, January 1, 2023 12:00 AM +Tuesday, June 6, 2079 11:00 PM +~~END~~ + + +select * from format_dep_func_smalldatetime() +go +~~START~~ +smalldatetime +1990-05-23 00:00:00.0 +~~END~~ + + +-- time +select * from format_dep_view_time +go +~~START~~ +nvarchar + + + + +~~END~~ + + +select * from format_datetime_dep_view_time +go +~~START~~ +nvarchar + + + + +~~END~~ + + +select * from format_datetime_dep_view_time2 +go +~~START~~ +nvarchar +00:00:00.123450 +03:53:59 +15:05:45 +23:59:59.123450 +~~END~~ + + +exec format_dep_proc_time +GO +~~START~~ +nvarchar + + + + +~~END~~ + + +select * from format_dep_func_time() +go +~~START~~ +time +00:00:00.1234500 +~~END~~ + + +-- tinyint +select * from format_dep_view_tinyint +go +~~START~~ +nvarchar +$0 +$31 +$255 +~~END~~ + + +exec format_dep_proc_tinyint +GO +~~START~~ +nvarchar +$0.00 +$31.00 +$255.00 +~~END~~ + + +-- smallint +select * from format_dep_view_smallint +go +~~START~~ +nvarchar +($2,456.000000) +($62.000000) +$282.000000 +$2,456.000000 +~~END~~ + + +exec format_dep_proc_smallint +GO +~~START~~ +nvarchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The culture parameter "aa-DJ" provided in the function call is not supported.)~~ + + +-- int +select * from format_dep_view_int +go +~~START~~ +nvarchar +($2,147,483.000000) +($586.000000) +$7,869.000000 +$2,147,483.000000 +~~END~~ + + +select * from format_numeric_dep_view_int +go +~~START~~ +nvarchar +($2,147,483.000000) +($586.000000) +$7,869.000000 +$2,147,483.000000 +~~END~~ + + +exec format_dep_proc_int +GO +~~START~~ +nvarchar +($2,147,483.00) +($586.00) +$7,869.00 +$2,147,483.00 +~~END~~ + + +-- bigint +select * from format_dep_view_bigint +go +~~START~~ +nvarchar +($9,223,372,036,854.000000) +($352.000000) +$2,822.000000 +$9,223,372,036,854.000000 +~~END~~ + + +exec format_dep_proc_bigint +GO +~~START~~ +nvarchar +($9,223,372,036,854.00) +($352.00) +$2,822.00 +$9,223,372,036,854.00 +~~END~~ + + +-- decimal +select * from format_dep_view_decimal +go +~~START~~ +nvarchar +($8,999,999,999.099090) +($352.000000) +$5,478.000000 +$8,999,999,999.999990 +~~END~~ + + +exec format_dep_proc_decimal +GO +~~START~~ +nvarchar +($8,999,999,999.10) +($352.00) +$5,478.00 +$9,000,000,000.00 +~~END~~ + + +-- numeric +select * from format_dep_view_numeric +go +~~START~~ +nvarchar +($8,999,999,999.099000) +($352.000000) +$5,478.000000 +$8,999,999,999.999900 +~~END~~ + + +exec format_dep_proc_numeric +GO +~~START~~ +nvarchar +($8,999,999,999.10) +($352.00) +$5,478.00 +$9,000,000,000.00 +~~END~~ + + +-- real +select * from format_dep_view_real +go +~~START~~ +nvarchar +($340,000,000,000,000,000,000,000,000,000,000,000,000.000000000) +($331,234,600,000,000,000,000,000,000,000,000,000,000.000000000) +($331,234,100,000,000,000,000,000,000,000,000,000,000.000000000) +($22.123400000) +$22.123400000 +$22.123410000 +$331,234,600,000,000,000,000,000,000,000,000,000,000.000000000 +$340,000,000,000,000,000,000,000,000,000,000,000,000.000000000 +~~END~~ + + +exec format_dep_proc_real +GO +~~START~~ +nvarchar +($340,000,000,000,000,000,000,000,000,000,000,000,000.00) +($331,234,600,000,000,000,000,000,000,000,000,000,000.00) +($331,234,100,000,000,000,000,000,000,000,000,000,000.00) +($22.12) +$22.12 +$22.12 +$331,234,600,000,000,000,000,000,000,000,000,000,000.00 +$340,000,000,000,000,000,000,000,000,000,000,000,000.00 +~~END~~ + + +-- float +select * from format_dep_view_float +go +~~START~~ +nvarchar +($179,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.000000000) +($340,000,000,000,000,000,000,000,000,000,000,000,000.000000000) +$35.367500000 +$340,000,000,000,000,000,000,000,000,000,000,000,000.000000000 +$179,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.000000000 +~~END~~ + + +exec format_dep_proc_float +GO +~~START~~ +nvarchar +($179,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.00) +($340,000,000,000,000,000,000,000,000,000,000,000,000.00) +$35.37 +$340,000,000,000,000,000,000,000,000,000,000,000,000.00 +$179,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.00 +~~END~~ + + +-- smallmoney +select * from format_dep_view_smallmoney +go +~~START~~ +nvarchar +($214,478.364800000) +$435,627.143500000 +($435,627.143500000) +$214,478.364700000 +~~END~~ + + +exec format_dep_proc_smallmoney +GO +~~START~~ +nvarchar +($214,478.36) +$435,627.14 +($435,627.14) +$214,478.36 +~~END~~ + + +-- money +select * from format_dep_view_money +go +~~START~~ +nvarchar +($92,233,720.580800000) +($214,478.364800000) +$435,627.143500000 +$214,478.364700000 +$92,233,720.580700000 +~~END~~ + + +exec format_dep_proc_money +GO +~~START~~ +nvarchar +($92,233,720.58) +($214,478.36) +$435,627.14 +$214,478.36 +$92,233,720.58 +~~END~~ + + +-- real +select * from format_dep_view_real2 +go +~~START~~ +nvarchar +($34.000000000) +($34.000000000) +($331,234,700,000,000,000,000,000,000,000,000,000,000.000000000) +$22,123.460000000 +$22.123410000 +$331,234,600,000,000,000,000,000,000,000,000,000,000.000000000 +$340,000,000,000,000,000,000,000,000,000,000,000,000.000000000 +~~END~~ + + +exec format_dep_proc_real2 +GO +~~START~~ +nvarchar +($34.00) +($34.00) +($331,234,700,000,000,000,000,000,000,000,000,000,000.00) +$22,123.46 +$22.12 +$331,234,600,000,000,000,000,000,000,000,000,000,000.00 +$340,000,000,000,000,000,000,000,000,000,000,000,000.00 +~~END~~ + + +-- float +select * from format_dep_view_float2 +go +~~START~~ +nvarchar +($331,234,678,912,346,000,000,000,000,000,000,000,000.000000000) +$3.312348966 +$3.312348966 +$3.312348966 +$3.312348966 +$3.312348966 +$33,123,489,656,565,100.000000000 +$3.312348966 +$3.312348966 +$351,234,567,891,026,000.000000000 +~~END~~ + + +exec format_dep_proc_float2 +GO +~~START~~ +nvarchar +($331,234,678,912,346,000,000,000,000,000,000,000,000.00) +$3.31 +$3.31 +$3.31 +$3.31 +$3.31 +$33,123,489,656,565,100.00 +$3.31 +$3.31 +$351,234,567,891,026,000.00 +~~END~~ + diff --git a/test/JDBC/expected/forxml-vu-cleanup.out b/test/JDBC/expected/forxml-vu-cleanup.out index 91cb7982ee..45deb7b5e2 100644 --- a/test/JDBC/expected/forxml-vu-cleanup.out +++ b/test/JDBC/expected/forxml-vu-cleanup.out @@ -4,9 +4,9 @@ drop procedure forxml_vu_p_employee_select; go drop procedure forxml_vu_p_employee_select2; go -drop view forxml_vu_v1; +drop view forxml_vu_view1; go -drop view forxml_vu_v2; +drop view forxml_vu_view2; go drop view forxml_vu_v_cte1; go @@ -26,3 +26,11 @@ drop table forxml_vu_t_employees; go drop table forxml_vu_t_employees2; go +drop procedure forxml_vu_p_nullval1 +go +drop procedure forxml_vu_p_nullval2 +go +drop procedure forxml_vu_p_nullval3 +go +drop procedure forxml_vu_p_nullval4 +go diff --git a/test/JDBC/expected/forxml-vu-prepare.out b/test/JDBC/expected/forxml-vu-prepare.out index 6f21154263..e4d0df4e6b 100644 --- a/test/JDBC/expected/forxml-vu-prepare.out +++ b/test/JDBC/expected/forxml-vu-prepare.out @@ -227,11 +227,11 @@ end; go -- Test for xml in create view -create view forxml_vu_v1 (col1) as select * from forxml_vu_t1 for xml raw, type; +create view forxml_vu_view1 (col1) as select * from forxml_vu_t1 for xml raw, type; go -- Test for xml on pure relational view -create view forxml_vu_v2 (col1, col2) as select * from forxml_vu_t1; +create view forxml_vu_view2 (col1, col2) as select * from forxml_vu_t1; go -- Test for xml and union all @@ -337,3 +337,20 @@ go create procedure forxml_vu_p_strvar @pid int, @str varchar(10) as select * from forxml_vu_t1 where id = @pid and a = @str for xml raw; go + +-- test null value handling in datetime, smalldatetime, datetime2, and datetimeoffset +create procedure forxml_vu_p_nullval1 as +select cast(null as datetime) for xml path; +go + +create procedure forxml_vu_p_nullval2 as +select cast(null as smalldatetime) for xml path; +go + +create procedure forxml_vu_p_nullval3 as +select cast(null as datetime2) for xml path; +go + +create procedure forxml_vu_p_nullval4 as +select cast(null as datetimeoffset) for xml path; +go diff --git a/test/JDBC/expected/forxml-vu-verify.out b/test/JDBC/expected/forxml-vu-verify.out index bf29fb302f..e5ad35aaa9 100644 --- a/test/JDBC/expected/forxml-vu-verify.out +++ b/test/JDBC/expected/forxml-vu-verify.out @@ -16,7 +16,7 @@ ntext ~~END~~ -select * from forxml_vu_v1; +select * from forxml_vu_view1; go ~~START~~ xml @@ -25,7 +25,7 @@ xml -- Test for xml on view with xml column -select * from forxml_vu_v1 for xml path; +select * from forxml_vu_view1 for xml path; go ~~START~~ ntext @@ -33,7 +33,7 @@ ntext ~~END~~ -select * from forxml_vu_v2 for xml path; +select * from forxml_vu_view2 for xml path; go ~~START~~ ntext @@ -93,3 +93,35 @@ go ntext ~~END~~ + +exec forxml_vu_p_nullval1 +go +~~START~~ +ntext + +~~END~~ + + +exec forxml_vu_p_nullval2 +go +~~START~~ +ntext + +~~END~~ + + +exec forxml_vu_p_nullval3 +go +~~START~~ +ntext + +~~END~~ + + +exec forxml_vu_p_nullval4 +go +~~START~~ +ntext + +~~END~~ + 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..679cb963a1 --- /dev/null +++ b/test/JDBC/expected/four-part-names-vu-verify.out @@ -0,0 +1,463 @@ +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~~ + + +-- Create procedure whose body contains four-part object name +CREATE PROCEDURE fpn_vu_prepare__fpn_proc AS SELECT * FROM bbf_fpn_server.master..fpn_table +GO + +-- Create function whose body contains four-part object name +CREATE FUNCTION fpn_vu_prepare__fpn_func() +RETURNS INT +AS +BEGIN +DECLARE @i int +SELECT @i = COUNT(*) FROM bbf_fpn_server.master.dbo.fpn_table +RETURN @i +END +GO + +EXEC fpn_vu_prepare__fpn_proc +GO +~~START~~ +int#!#varchar +1#!#one +2#!#two +3#!#three +4#!#four +~~END~~ + + +SELECT fpn_vu_prepare__fpn_func() +GO +~~START~~ +int +4 +~~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 +DROP PROCEDURE fpn_vu_prepare__fpn_proc +DROP FUNCTION fpn_vu_prepare__fpn_func() +GO diff --git a/test/JDBC/expected/fts-contains-vu-cleanup.out b/test/JDBC/expected/fts-contains-vu-cleanup.out new file mode 100644 index 0000000000..a3ad31a39a --- /dev/null +++ b/test/JDBC/expected/fts-contains-vu-cleanup.out @@ -0,0 +1,40 @@ +-- tsql user=jdbc_user password=12345678 +-- enable CONTAINS +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +DROP PROCEDURE fts_contains_vu_prepare_p1; +GO + +DROP FULLTEXT INDEX ON fts_contains_vu_t; +GO + +DROP TABLE fts_contains_vu_t; +GO + +DROP VIEW fts_contains_pgconfig_v1 +GO + +-- disable CONTAINS +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO +~~START~~ +text +strict +~~END~~ + + +-- psql +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = off; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + diff --git a/test/JDBC/expected/fts-contains-vu-prepare.out b/test/JDBC/expected/fts-contains-vu-prepare.out new file mode 100644 index 0000000000..1fefb90b7c --- /dev/null +++ b/test/JDBC/expected/fts-contains-vu-prepare.out @@ -0,0 +1,5071 @@ +-- psql +-- enable CONTAINS +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = on; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql user=jdbc_user password=12345678 +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +-- Create table for full text search CONTAINS predicate +CREATE TABLE fts_contains_vu_t (id int NOT NULL, txt text) +GO + +-- Should throw error because there exist no full-text index for the table +SELECT * FROM fts_contains_vu_t WHERE CONTAINS(txt, 'run'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot use a CONTAINS or FREETEXT predicate on table or indexed view 'fts_contains_vu_t' because it is not full-text indexed.)~~ + + +CREATE UNIQUE INDEX fts_contains_vu_t_id_idx ON fts_contains_vu_t(id); +GO + +CREATE FULLTEXT INDEX ON fts_contains_vu_t(txt) KEY INDEX fts_contains_vu_t_id_idx; +GO + +-- Full text search @query_string using CONTAINS +-- Optional parameter @top_n to filter top n rows of output +CREATE PROCEDURE fts_contains_vu_prepare_p1 + @query_string text, + @top_n int = -1 +AS +BEGIN + IF @top_n >= 0 + BEGIN + SELECT TOP(@top_n) * FROM fts_contains_vu_t WHERE CONTAINS(txt, @query_string) ORDER BY id + END + ELSE + BEGIN + SELECT * FROM fts_contains_vu_t WHERE CONTAINS(txt, @query_string) ORDER BY id + END +END +GO + +CREATE VIEW fts_contains_pgconfig_v1 AS +( + SELECT CAST((sys.babelfish_fts_contains_pgconfig('like')) AS text) +) +GO + +-- initialize table: txt column has 1000 sentences from NOW corpus +INSERT INTO fts_contains_vu_t VALUES (1, '

Sol Yurick , the writer whose 1965 novel " The Warriors " was adapted into a film 14 years later -- which then became one of the best adapted works ever in video gaming -- died this weekend ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (2, ' He was 88 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (3, 'Yurick ''s work itself was a loose adaptation of a story told 2,300 years before : Anabasis , which chronicles the journey of Greek mercenaries through hostile territory after the death of their leader ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (4, ' Yurick ''s book , and The Warriors both open with a grand council of street gangs , convened in the Bronx , and the murder of the leader who called for the gathering ( Cyrus , a direct reference to the leader of the Greeks in Anabasis ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (5, ' But the stories then diverge significantly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (6, 'Walter Hill , the director of The Warriors , strove to give a comic-book depiction of the gang ''s flight from the Bronx back to their Coney Island turf ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (7, ' ( Indeed , in Yurick ''s book , the gang ''s mascot , Junior , reads a comic book version of @ @ @ @ @ @ @ @ @ @ , each faction was given a name and a costume theme invoking it , typified by the iconic " Baseball Furies " the protagonist Warriors fight in Riverside Park ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (8, ' After making their way through rival gangs '' turf in Manhattan and then back to Coney Island , the Warriors defeat the gang responsible for Cyrus '' death ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (9, 'Advertisement') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (10, 'The Warriors became a cult hit , partly because its exaggerated portrayal of New York City ''s lawlessness fit with the image of violent crime and decay that blighted the city in the late 1970s ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (11, ' A staple of Saturday and Sunday afternoon movie programming on UHF stations , the film faded from popular memory until Rockstar resurrected it as a video game 26 years later ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (12, 'Sponsored') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (13, 'The Warriors , released in 2005 for the Xbox and PS2 , began with a three-minute recreation of the film ''s opening sequence ( shown above ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (14, ' Set to the blood pumping guitar and synthesizer of Barry Vorzon ''s original soundtrack , it ''s one of the best openings a video game has ever had ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (15, ' Critics familiar @ @ @ @ @ @ @ @ @ @ well in a year full of big hits ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (16, ' Primarily a brawler , with some limited open-world features , the game also served as a canonical prologue to the all-gang meeting in the Bronx ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (17, ' It is playable only on the PlayStation 2 and original Xbox ; a version for the PSP was released in 2007') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (18, ' That ''s What They Say : Dialect Society chooses its words of the year') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (19, 'For this week ''s edition of " That ''s What They Say , " University of Michigan Professor Anne Curzan spoke with us from Boston , where she was attending the American Dialect Society ''s annual meeting , whose 200 members voted on their " Word of the Year ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (20, 'Rina Miller : So the winner is ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (21, 'Anne : The winner is " hashtag ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (22, ' " It was a surprise entry ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (23, ' It was nominated from the floor ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (24, ' I must admit , I went in thinking " fiscal cliff " had this hands down ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (25, ' I thought there was no way anything would beat that , but fiscal cliff did n''t even make the runoff ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (26, ' It was hashtag vs') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (27, ' marriage equality ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (28, 'Rina : Why hashtag ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (29, 'Anne : The argument was that while the word hashtag has been around since 2007 , this was the year of the hashtag ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (30, ' This was the year that hashtag was everywhere in the Twittersphere and beyond @ @ @ @ @ @ @ @ @ @ , making memes go viral ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (31, 'Rina : And what were the winners in some of the other categories ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (32, 'Anne : Marriage equality , which was in the runoff for word of the year , actually won most likely to succeed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (33, ' And I thought it was a very interesting entry ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (34, ' The argument was that as the country has changed its attitudes about marriage equality , we ''ve seen the terminology shift from same-sex marriage or gay marriage to marriage equality ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (35, ' And people pointed out that when textbooks write this up as a movement , it will be about the movement for marriage equality ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (36, 'Rina : Tell us about some of the other categories ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (37, 'Anne : One of my favorites , most years , is the most creative word of the year ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (38, ' And there were two terrific candidates this year ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (39, ' One is " mansplaining , " which is defined as a man ''s condescending explanation to a female audience ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (40, ' It ''s designed to capture a certain kind of male behavior ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (41, ' It did mean that during the discussion of @ @ @ @ @ @ @ @ @ @ talking because they could easily be accused of mansplaining every time they tried to say anything , even though it was a mixed-gender audience ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (42, 'Rina : That ''s never happened to me , has it to you , Anne ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (43, 'Anne : No , never ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (44, 'The mansplaining was up against " gate lice " -- a description of passengers on an airplane who crowd around the gate waiting to board ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (45, 'Rina : I love that !') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (46, 'Anne : I loved it , too , and I particularly liked the singular , which is gate louse ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (47, 'Rina : And who does n''t know that ? Maybe we ''ve even been a louse ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (48, 'Anne : And now we have such a great way to talk about it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (49, ' We can say , " Look at all the gate lice ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (50, 'Rina : There ''s also the most unnecessary and the most outrageous categories ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (51, ' Those are more serious ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (52, 'Anne : They are more serious ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (53, ' And this year the same phrase won in both categories ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (54, ' It @ @ @ @ @ @ @ @ @ @ Senate candidate Todd Akins ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (55, ' And someone pointed out when we were voting for most unnecessary , that it came up again under most outrageous on the ballot ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (56, ' And someone yelled out , " It should win both ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (57, ' " And it did ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (58, 'Rina : And which word was least likely to succeed ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (59, 'Anne : That was a tie ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (60, ' One of the first I remember ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (61, ' It was a tie between " YOLO , " which our listeners over about 25 or 30 may be less familiar with ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (62, ' It is an acronym for " you only live once ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (63, ' " It came to prominence this year from the rapper , Drake ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (64, ' He had a song in which he talked about you only live once -- YOLO -- and I think there are a number of young people who got YOLO tattoos , which they are going to come to regret , because students tell me it is already very unhip ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (65, 'YOLO tied with " phablet , " which is apparently a mid-sized electronic device between a smart phone and a tablet @ @ @ @ @ @ @ @ @ @ Anne : For the most useful , we had two combining forms ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (66, ' " Pocalypse " or " mageddon , " which you ''ll hear people attach to things like " snowmaggedon " or " oilpocalypse " to describe a huge oil spill as a hyperbolic way to talk about a catastrophe ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (67, 'Rina : There had to be something that came out of the elections ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (68, 'Anne : The election phrase of the year is " binders full of women ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (69, ' " After presidential candidate Mitt Romney said that , it instantly became a hashtag , and many people have probably seen it circulating online ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (70, ' It beat " 47 percent , " which was also up for word of the year ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (71, ' So both 47 percent and " fiscal cliff " did n''t win anything ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (72, ' A sublime croissant at French Tart in Grant City , Staten Island ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (73, 'French Tart chef Laurent Chavenet claims to work in the only authentic French cafe and restaurant in Staten Island ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (74, ' And he just might be right ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (75, ' Opened in 2009 , French Tart is one of those hidden gems that food lovers so often hear about in the outer boroughs , but so rarely find ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (76, ' Baked fresh every morning by Chavenet himself , the croissants are a work of art ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (77, ' The texture runs from crispy on the outside to soft and airy on the inside ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (78, ' According to Chavenet , the secret to making a great croissant is in quality ingredients , especially the butter , and the folding of the dough , which Chavenet demonstrates on a napkin ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (79, ' While the plain croissant is outstanding , the almond croissant is truly world-class ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (80, ' Moist , sweet and decadent , it ''s more of a dessert than a breakfast item , but go ahead and dig in any time of day ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (81, ' After all , life is short ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (82, ' Eat dessert @ @ @ @ @ @ @ @ @ @ Colson Patisserie , in Park Slope , uses two types of flour in its croissants ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (83, 'In 1986 , pastry chef Hubert Colson first opened his famed pastry shop in Mons , Belgium ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (84, ' Barely 20 years later , Yonatan Israel , a French filmmaker searching for structure and opportunity in life , opened his own shop as a tribute to his favorite pastry chef ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (85, ' And so the Park Slope outpost of Colson Patisserie was born ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (86, ' What a gift for pastry lovers in Brooklyn ! Colson ''s croissants ( $2') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (87, '45 ) seem light enough to float above the table and rich enough to melt in your mouth ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (88, ' Two types of flour are used in the dough , which is then folded six to eight times ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (89, ' Eighty croissants are made daily for the pastry shop , which is small but well-lit by a storefront of large windows ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (90, ' Sweet but not candied , these croissants taste like a big puff of flaky butter , which is just what every New Yorker needs to start off their day ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (91, ' As Israel says , " New York is the @ @ @ @ @ @ @ @ @ @ to change that ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (92, 'You ca n''t talk about croissants in New York City without mentioning master pastry chef Laurent Dupal and his Spring St') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (93, ' shop Ceci-Cela ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (94, ' Since his quaint cafe opened in 1992 , Dupal has consistently made some of the flakiest , butteriest , airiest croissants ( $2 ) in the five boroughs ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (95, ' Dupal credits fresh ingredients , a controlled setting and years of experience for the excellent taste of his croissants , hundreds of which are sold a day in the patisserie ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (96, ' In fact , Dupal compares baking croissants with raising a child ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (97, ' " Everyone does it differently , " he says , " and , no matter what , you have to adjust to the temperament of the dough , which ca n''t be too thin or too thick ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (98, ' " Take some home for the whole family ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (99, ' A pack of six frozen croissants costs $7 and can be baked at home ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (100, 'YOUR TWO CENTS') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (101, 'The croissant at Chock Full o '' Nuts Cafe ( 1611 Avenue M , Brooklyn ) is very buttery inside and outside @ @ @ @ @ @ @ @ @ @ good with a side of butter/jelly along with a cup of regular or flavored coffee or chai latte or tea ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (102, ' Service is very courteous , but a little slow ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (103, ' -- Tzivia M') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (104, 'Stork ''s Bakery , located at 12-42 150th St') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (105, ' in Whitestone , makes the perfect croissant ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (106, ' Its golden , flaky , light crust is pleasing to the eye , and it draws you into its succulent flavor , which is light , rich and satisfying ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (107, ' Be sure to get there early in the a') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (108, ' if you wish to partake in this culinary delight ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (109, ' They sell out quickly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (110, ' -- Carol D') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (111, 'The best croissant in the city can be found at City Bakery ( 3 W') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (112, ' 18th St') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (113, ' in Manhattan ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (114, ' The pretzel croissant , as it ''s called , combines the rich buttery body of a typical croissant with the salty crispness of a pretzel') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (115, ' -- Christopher O') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (116, 'The croissants at The Standard hotel are the tastiest in the city ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (117, ' The secret is in the sourdough they add to it ! Also , buttery and flaky as all @ @ @ @ @ @ @ @ @ @ the upper West Side has the best croissant I ''ve had in NYC ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (118, ' It ''s flaky on the outside , but buttery and perfectly doughy on the inside ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (119, ' It ''s the best croissant I ''ve had outside of Paris ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (120, ' -- Colman C') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (121, 'YOU SUGGEST IT , WE ''LL TEST IT') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (122, 'We ''re in search of the best of the city , but we need your help ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (123, ' Send your picks for the following , and we ''ll try them ! \n') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (124, ' Reflecting on a quarter-century of growth in Portland ''s performing arts scene') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (125, 'The highlight of the Portland Center for Performing Arts '' grand-opening in 1987 was a performance by high-wire artists Phillippe Petit and Ann Seward , which reflected the thrilling risk the city had taken with the project ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (126, ' Steven Nehl/The Oregonian') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (127, 'Stephanie Mulligan , who has been with Artists Repertory Theatre since the mid 1980s , knew the Portland theater scene in its younger , wilder days ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (128, ' " There were more trails of glitter than there are today -- I mean that literally , " she says ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (129, ' " I like to think there was a lot more nudity , but that might just be a trick of memory ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (130, 'These days , Portland theater , and the city ''s arts scene in general , is n''t so stripped down ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (131, ' But it is much more glittery , if not literally than metaphorically ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (132, ' Look around and you ''ll see it : the sparkle of widespread creative activity , the shine of technical and artistic quality ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (133, 'There ''s @ @ @ @ @ @ @ @ @ @ music -- most definitely in food , if you want to extend the definition of the creative culture -- and perhaps in other areas as well , this is Portland ''s golden age ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (134, ' Sure , the city ''s artsy eccentricities can grow ripe for lampooning , as the TV spoof " Portlandia " has proved ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (135, ' But such attention would be nonsensical ( or at least much more embarrassing ) if there was n''t more going on here than adult kickball leagues and mustache-growing contests , if many of the eccentrics were n''t really artists ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (136, 'A certain shoestring flamboyance , as Mulligan ''s recollections of leaner times suggest , is nothing new here ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (137, ' But the size , scope and solidity of the arts in Portland is something that ''s grown over the past quarter century ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (138, 'That 1987 and '' 88 marked a pivotal time in Portland arts was clear even then ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (139, ' More than a decade of planning and haggling was coming to fruition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (140, ' The idea for a set of new performance spaces began taking place around 1976 due to dissatisfaction with Civic Auditorium @ @ @ @ @ @ @ @ @ @ satisfying venue ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (141, ' In 1981 , voters passed a $19 million bond issue ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (142, ' Next came political squabbles , cost overruns ( from $25 million to $41 million by the time it opened ) and a scramble to find money for operating costs ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (143, ' But eventually the Civic was joined by the Arlene Schnitzer Concert Hall ( a refurbished 1928 movie palace ) and a new multi-use building next door ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (144, '" Ten or 20 years from now , few will remember all the effort , dreaming , planning and yes , the bickering , mistakes and accusations that marked the creation of the Portland Center for the Performing Arts , " The Oregonian ''s Joan Laatz wrote in August , 1987 , when the multi-use New Theater Building ( now named Antoinette Hatfield Hall ) opened ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (145, 'Meanwhile , city officials had been looking for an anchor tenant to take up residence in the center ''s the 900-seat space now known as the Newmark Theatre ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (146, ' A study commissioned by the Fred Meyer Trust concluded that not even the city ''s top existing theater company , Portland @ @ @ @ @ @ @ @ @ @ organizationally ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (147, ' Cynthia Fuhrman , a veteran theater marketing exec , recalls that Portland was the largest city in the country that did n''t have a company in the League of Resident Theatres , the association of major regional theaters ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (148, ' After being courted on and off for years , Ashland ''s Oregon Shakespeare Festival signed on , and its new satellite operation , dubbed Portland Center Stage , stepped into the lights in Nov') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (149, ' 1988 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (150, 'After seeing the new company in the new building , Time magazine said that Portland at last could stake a claim to sophistication and social significance ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (151, 'More so than social stature , the goal was for the PCPA to both bring more touring talents to town and give local troupes a comfortable home that would help them grow their audiences , and for PCS to provide a model of quality , stability and professionalism that might lift the community as a whole ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (152, ' The fear was that higher production costs in the new facilities would make things tougher for most local arts companies , and that the venerable OSF @ @ @ @ @ @ @ @ @ @ ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (153, '" There was so much buzz about OSF coming up , " recalls Beth Harper , who ''d soon launch what ''s now called Portland Actors Conservatory ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (154, ' " I was in a show at New Rose and everyone felt like , '' The big guys are coming and we ''ve never got that kind of attention ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (155, ' '' " " One of the things that still rings true , " Harper adds , " is the big boys are still the big boys and the small ones are still the small ones ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (156, 'Though perhaps not ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (157, ' Yes , Center Stage , which split from OSF to become an independent company in 1994 , remains atop the theatrical food chain ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (158, ' What were the largest or most active homegrown companies back in the late '' 80s -- Portland Rep , New Rose , Storefront Portland Civic Theater -- long ago folded ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (159, ' ( As Mulligan recalls , " It took about five years for the dust to settle -- unfortunately the dust was some fine companies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (160, ' " ) And as it did then , the @ @ @ @ @ @ @ @ @ @ stage a few shows a year in rented or makeshift spaces ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (161, 'Numerous factors are involved , not just the anchoring effects of PCPA and PCS , but the theater scene now has a broader range of companies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (162, ' Artists Repertory Theatre , once a scrappy little operation in rented space at the downtown YWCA , grew to become the city ''s No') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (163, ' 2 company , with a $2') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (164, '4 million budget and its own twin-auditorium home ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (165, ' Down the scale in budget , but punching above their weight artistically , Third Rail Rep , Portland Playhouse and Profile Theatre form a strong middle tier ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (166, 'However persistent the funding challenges of the dance world , a similar vertical growth , if you will , can be found ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (167, ' In the late '' 80s , Portland had both Ballet Oregon and Pacific Ballet Theatre ; for contemporary dance , Portland State University housed a concert series for touring groups and a top-notch resident company ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (168, ' Now , Oregon Ballet Theatre ( the result of a merger of the aforementioned ballet troupes ) survives , White Bird does concert presenting at @ @ @ @ @ @ @ @ @ @ Polaris Dance Theatre each have performance spaces and expanding reputations ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (169, '" I think the arts scene was like a young teenager then and has grown up a lot , " says Regional Arts & Culture Council executive director Eloise Damrosch , who moved to Portland in '' 87 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (170, ' " Our reputation as a place to visit has really skyrocketed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (171, ' I ''m struck when I open up the A&E and see all the options ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (172, ' There ''s a lot more happening , and such a range ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (173, 'Quantity is n''t the only thing that ''s changed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (174, '" Back then , there was this grittier , shoestring quality that imbued almost every company , " Mulligan says ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (175, ' " The dedication to art was inspiring ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (176, ' But when I look back at that earlier renaissance of the '' 80s , the truth was the talent pool of the city needed to step up ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (177, 'Jim Fullan , who has worked in marketing at Portland Opera and the Oregon Symphony , says the city has developed a " radically different sense of our place @ @ @ @ @ @ @ @ @ @ such an inferiority complex regarding Seattle , San Francisco and Los Angeles that it distrusted artistic ambition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (178, ' " The public would punish you for getting too big for your britches ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (179, ' The prevailing attitude was , '' It ''s good enough for us ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (180, ' We like it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (181, ' '' Now , that ''s totally gone ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (182, ' It ''s almost the opposite ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (183, ' If you ''re not aspiring to be world-class , you ''re not on the boat ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (184, ' The arts -- in tandem with food , beer and wine -- have raised us up ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (185, 'The building of the PCPA has n''t solved all of the performance-space issues for local companies ( there ''s a big , problematic gap between the 900-seat Newmark and the Schnitzer and Keller , which seat close to 3,000 ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (186, ' And it ''s notable that Center Stage had to move to a home of its own , a renovated 19th-century armory in the Pearl District , to begin fulfilling its potential as a truly vibrant hub for the theater scene ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (187, ' But those two big moves have , over time , proved @ @ @ @ @ @ @ @ @ @ other developments have helped shape the Portland of today ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (188, ' Some observers point to the fundraising success of John and Lucy Buchanan at the Portland Art Museum 1994 to 2005 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (189, ' " They actually made a case that a great city needs great art , " says BodyVox co-founder Jamey Hampton ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (190, ' " And that put a gauntlet down ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (191, 'Leadership changes in 2003 at Portland Opera , Oregon Ballet Theatre and the Oregon Symphony also marked a crucial transition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (192, ' Hampton points to Tom Manley , president of Pacific Northwest College of Art as " probably the best leader of an arts organization the city has ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (193, ' " PNCA has grown to be a leading creative and economic force in the Pearl District ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (194, ' and it ''s in the process of remaking how that neighborhood looks ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (195, ' It ''s not splashy , like when Pink Martini plays New Year ''s Eve at the Schnitz ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (196, ' It ''s quiet , but it ''s really foundational ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (197, 'Through it all , the essential challenges remain much the same : make good work , expand audiences , cultivate donors @ @ @ @ @ @ @ @ @ @ business model , away from a focus on big-money patrons and toward building long-term relationships with supporters of all sorts , nurturing them along the path from first-time ticket buyer to subscriber to contributor and so on ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (198, ' Others point out that the city is awash in heavily subsidized art -- but that the artists themselves provide the subsidy comes from the artists themselves , in the form of the second jobs , lack of health care , or multiple roommates that allow them to subsist as artists ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (199, 'All together , what ''s changed and what ''s stayed the same add up to an arts scene that , while still facing major challenges , has grown bigger , wider and better integrated into the world around it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (200, '" I do n''t think it happens in isolation , " Fuhrman says ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (201, ' " It ''s about the growth of the city as a whole ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (202, ' Ask Ars : Does Facebook auto-delete content after a certain period of time ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (203, 'Ars reader wants to create a page for an ancestor , but worries about losing content ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (204, 'In 1998 , Ask Ars was an early feature of the newly launched Ars Technica ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (205, ' Now , as then , it ''s all about your questions and our community ''s answers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (206, ' We occasionally dig into our question bag , provide our own take , then tap the wisdom of our readers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (207, ' To submit your own question , see our helpful tips page ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (208, 'I ask , because I want to use Facebook to create a historical timeline about an ancestor in my family so people can learn more about their heritage ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (209, ' I have Googled my question several times and all answers are confusing and mixed : some say everything stays on a FB page until you clean it off and others say Facebook deletes status updates and photos monthly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (210, 'This is an interesting way to use Facebook -- to create a page for someone who is not @ @ @ @ @ @ @ @ @ @ existed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (211, ' ( Typically , the question is the other way around : what to do with someone ''s existing Facebook account after they pass away ? ) And given the level of confusion constantly floating around about Facebook ''s data retention policies , it ''s no surprise that it might be hard to pinpoint exactly when ( if ever ) information gets deleted from the social network ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (212, 'We store data for as long as it is necessary to provide products and services to you and others , including those described above ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (213, ' Typically , information associated with your account will be kept until your account is deleted ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (214, ' For certain categories of data , we may also tell you about specific data retention practices ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (215, 'Just to be sure , we reached out to Facebook to confirm this is indeed the policy for the above use case ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (216, ' The company confirmed that as long as you have not deleted the content yourself -- or in the case of a message between two people , both people have not deleted it -- the content should stay online indefinitely @ @ @ @ @ @ @ @ @ @ to keep in mind about this policy ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (217, ' If you ever do want to delete the content , you should know that it ''s not likely to disappear instantly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (218, ' As you may remember , we followed a thread for several years over how fast photos are deleted from Facebook ''s servers once you delete them from the site ; as of late 2012 , we verified that photos indeed appear to be removed within 30 days of deletion ( our tests showed they were actually removed much faster ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (219, 'It ''s not just about photos , though ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (220, ' As outlined in the same Data Use Policy referenced above , there are major differences between deactivating an account versus deleting an account , should you choose to eventually remove the account you created for your ancestor ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (221, ' Many Facebook users mistakenly think that deactivating their accounts equals deletion , but that is not so :') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (222, 'Deactivating your account puts your account on hold ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (223, ' Other users will no longer see your timeline , but we do not delete any of your information ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (224, ' Deactivating an account is the @ @ @ @ @ @ @ @ @ @ because you might want to reactivate your account at some point in the future ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (225, ' You can deactivate your account on your account settings page ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (226, 'Your friends will still see you listed in their list of friends while your account is deactivated ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (227, 'So when you deactivate your ancestor ''s account , it ''s not really going anywhere ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (228, ' The data is still there , lurking somewhere on Facebook ''s servers , even if the " friends " of that account can no longer see it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (229, 'Deletion , however , is another matter :') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (230, 'When you delete an account , it is permanently deleted from Facebook ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (231, ' It typically takes about one month to delete an account , but some information may remain in backup copies and logs for up to 90 days ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (232, ' You should only delete your account if you are sure you never want to reactivate it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (233, 'Certain information is needed to provide you with services , so we only delete this information after you delete your account ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (234, ' Some of the things you do on Facebook are @ @ @ @ @ @ @ @ @ @ group or sending someone a message ( where your friend may still have a message you sent , even after you delete your account ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (235, ' That information remains after you delete your account ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (236, 'I often see Facebook users confusing these two things ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (237, ' They usually become alarmed when they ''ve deactivated an account , only to have all the old information show up again when they go to " register " a new account ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (238, ' But if you actually go through with a real deletion , the information should n''t be there past 90 days -- and hopefully it will be gone sooner ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (239, '

NEW YORK -- An associate of a notorious Russian arms dealer was arrested in Australia and charged with conspiring to buy planes so that weapons could be transported to the world ''s bloodiest conflicts , a U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (240, ' prosecutor announced Thursday ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (241, 'Syrian-born American Richard Ammar Chichakli was arrested Wednesday at the request of U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (242, ' authorities on charges that he conspired with Russian arms merchant Viktor Bout and others to try to buy the planes from two U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (243, ' companies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (244, 'Sukree Sukplang / Reuters file') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (245, 'Suspected Russian arms dealer Viktor Bout speaks to the media after arriving at a Bangkok criminal court August 20 , 2010 , ahead of an expected appeal court verdict on whether to extradite him to the U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (246, 'His arrest was first confirmed by the Australian Fairfax Media news organization , which reported Thursday that he was arrested in Melbourne after applying for a post in the government Protective Service Office , a law enforcement agency ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (247, ' The news service reported that he said nothing during a Thursday hearing at the Melbourne Magistrates Court ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (248, 'A lawyer for Chichakli @ @ @ @ @ @ @ @ @ @ Almustafa ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (249, ' Chichakli was held pending the processing of a U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (250, ' extradition request ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (251, 'Victoria state police spokeswoman Jessica Rosewarne confirmed Chichakli was caught after applying for the government post ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (252, '" He was identified as a person of interest through routine background checks as part of the application process , " she said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (253, ' " He had not been offered employment with Victoria police or started any training ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (254, ' Attorney Preet Bharara , the chief federal prosecutor in New York , said Chichakli " consorted with the world ''s most notorious arms trafficker in the purchase of aircraft that would be used to transport weapons to some of the world ''s bloodiest conflict zones , in violation of international sanctions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (255, 'Michele M') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (256, ' Leonhart , administrator of the Drug Enforcement Administration , said the international law enforcement community has long recognized Chichakli as a key criminal facilitator in Bout ''s global weapons trafficking regime ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (257, '" His arrest means the world is safer and more secure , " she said in a release ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (258, 'Merchant of Death Bout is a former @ @ @ @ @ @ @ @ @ @ his 1990s-era notoriety for running a fleet of aging Soviet-era cargo planes to conflict-ridden hotspots in Africa ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (259, ' He also inspired the arms dealer character played by Nicolas Cage in the 2005 film " Lord of War ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (260, 'An indictment against Chichakli in U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (261, ' District Court in Manhattan and other court documents accuse Chichakli of working as a close associate of Bout since at least the mid-1990s to assemble a fleet of cargo planes capable of shipping weapons and military equipment to various parts of the world , including Africa , South America and the Middle East ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (262, 'Prosecutors say the arms have helped fuel conflicts and support regimes in Afghanistan , Angola , The Democratic Republic of the Congo , Liberia , Rwanda , Sierra Leone and Sudan ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (263, 'Over the years , Chichakli has weaved a colorful biography of his past but often repudiated his comments under the glare of law enforcement scrutiny ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (264, 'He has claimed to have befriended a young Osama bin Laden during college days at Riyadh University in Saudi Arabia ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (265, ' He also claimed a stint in the U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (266, ' Army @ @ @ @ @ @ @ @ @ @ Gulf War ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (267, 'The indictment accuses Chichakli and Bout of violating sanctions by arranging to buy two Boeing aircraft from U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (268, ' companies in 2007 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (269, ' It says they electronically transferred more than $1') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (270, '7 million through banks in New York and into bank accounts in the U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (271, ' , though the money was blocked by the U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (272, ' Department of the Treasury before it reached the aviation companies '' accounts ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (273, 'The Treasury Department had imposed an asset freeze against Chichakli in April 2005 as part of larger financial sanctions aimed at the Bout network ''s dealings with the dictatorial regime of Liberian President Charles Taylor ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (274, ' The department called Chichakli , who once ran a small conglomerate of Texas-based businesses from a Dallas suburb , " Bout ''s U') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (275, '-based chief financial officer ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (276, 'If convicted , Chichakli could face up to 20 years in prison on each of nine counts , including conspiracy to violate the International Emergency Economic Powers Act , money laundering conspiracy , wire fraud conspiracy and wire fraud ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (277, '

IRELAND ''S Olympic bronze medallist Michael Conlan and reigning European champion Andrew Selby from Wales resume one of amateur boxing ''s most compelling rivalries when the World Series of Boxing heads to Bethnal Green ''s historic York Hall tomorrow') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (278, 'Conlan will be representing the USA Knockouts franchise in the team competition while Selby intends to do his bit to extend the GB Lionhearts '' unbeaten home record , but the real allure of the contest lies in the simple notion of repeat or revenge ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (279, 'Selby beat Conlan by a single point in a hotly contested flyweight quarter-final in the World Championships in Baku in 2011 , the Welshman going on to reach the final where he lost an equally slim verdict to Misha Aloian of Russia ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (280, '" I would n''t say there is bad blood between us but there is certainly some tension because he won our last fight by a point and I thought I had done enough to win , " the 21-year-old Conlan told the Press Association ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (281, 'The pair narrowly missed the chance of a return match @ @ @ @ @ @ @ @ @ @ beaten in the quarter-final by Cuba ''s brilliant Robeisy Ramirez Carrazana ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (282, 'Carrazana went on to clearly beat Conlan in the last four , consigning the Irishman to a bronze medal which saw him return home to a hero ''s welcome and his own mural on the corner of his home street in west Belfast ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (283, 'Thursday ''s bout will be the first time Conlan has fought since his defeat to the Cuban ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (284, '" It has been a very enjoyable time since the Olympics but I would n''t say it has affected my training very much , " Conlan said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (285, '" I have been in the gym for the last 12 weeks and the only difference is I get recognised more , which the mural at the bottom of my street probably helps ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (286, ' It was very unexpected and a great honour for me ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (287, 'While Selby was bitterly disappointed to return home from the Olympics without a medal , he remains one of the best 52kg fighters in the business , having long since shrugged off the chronic weight problems that once @ @ @ @ @ @ @ @ @ @ a pasty this week for the first time in ages , " Selby said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (288, '" There was a time when I could n''t eat for two days before a bout and had to spend the whole time running and skipping to get the weight off ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (289, '" It definitely affected my performances but I ''ve got over it now and I feel so much stronger and sharper ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (290, ' I ca n''t wait to get back in the ring with Michael ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (291, '" It ''s going to be a very tough fight ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (292, ' I know he ''s going to be wanting revenge ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (293, 'Despite its rather contrived franchise system which will see two of Conlan ''s Ireland team-mates - John Joe Nevin and Joe Ward - lining up for the opposite side , the WSB is clearly made for the likes of Conlan and Selby , intent on keeping the lure of pros at bay ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (294, 'Conlan says he is prepared to commit to Rio 2016 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (295, 'He said : " It ''s a long way away but I definitely want to win a @ @ @ @ @ @ @ @ @ @ ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (296, '" The WSB gives a great incentive not to go pro because you get paid for having top fights ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (297, ' It makes you wonder whether it is really worth turning over ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (298, ' There ''s not so much money in the pros these days unless you ''re a superstar ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (299, 'Selby will also stay amateur at least up to next year ''s Commonwealth Games in Glasgow , when he will aim to dispel the dismal memory of his weight-drained , second round defeat to Haroon Khan in Delhi ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (300, '" I ''ve got unfinished business with the Commonwealths and the fact it ''s in Glasgow makes it something great to aim for , " Selby said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (301, '" I want to go there and get a gold , and then it will be time for me to sit down and think about Rio ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (302, 'At least for the time being , the rivalry between two of the world ''s best amateur flyweight is set to develop ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (303, ' Thursday night ''s fight will prove who has claimed the upper-hand in the post-London glow ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (304, ' Shakira launches online baby shower') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (305, 'Shakira and her boyfriend Gerard Pique are hosting an online baby shower ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (306, 'The 35-year-old Columbian singer - who is expecting their first child , a baby boy , to arrive '' '' imminently '' '' - has invited fans to join their virtual charity bash , where they can purchase essential baby gifts that will support UNICEF and benefit some of the world ''s most vulnerable babies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (307, 'In an invitation posted on Twitter today ( 16') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (308, '13 ) , the couple wrote : '' '' To celebrate the arrival of our first child , we hope that , in his name , other less privileged children in the world can have their basic needs covered through gifts and donations ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (309, ' Thank you for sharing this unforgettable moment with us ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (310, 'The online baby shower engages social media fans by enabling them to join the popstar and her FC Barcelona star beau in their virtual living room , where they can buy '' Inspired Gifts '' such as mosquito nets , polio vaccines and baby-weighing scales @ @ @ @ @ @ @ @ @ @ of the poorest corners of the globe ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (311, 'Guests are welcomed by a personal video message from Shakira and Gerard ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (312, 'After purchasing an '' Inspired Gift '' , fans will then receive a personal thank you message from the couple , and be able to view exclusive photos of them taken in December 2012 by Jaume Laiguana ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (313, 'Shakira has been dating FC Barcelona soccer player Gerard for around two years and previously said he is the '' '' best thing '' '' to ever happen to her , until she got pregnant ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (314, 'She said : '' '' This man is the best thing that could have happened in my life ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (315, ' And now the baby ! '' ''') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (316, 'Shakira only confirmed their relationship last year by posting a picture of them both together on Twitter and Facebook with a caption reading , '' '' I present to you my sunshine ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (317, ' '' '' in Spanish ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (318, 'The link to the Shakira and Gerard Pique ''s Virtual Baby Shower is here : http : //uni') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (319, 'cf/baby \n') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (320, '

ENTREPRENEUR and political activist Declan Ganley has agreed to pay the European Election expenses of Co Louth beef and cereal farmer Raymond O''Malley who failed to get elected , a court was told today ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (321, 'Mr Ganley , of Moyne Park , Moyne , Abbeyknockmoy , Tuam , Co Galway , had been sued by O''Malley in the Circuit Civil Court for ? 35,366 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (322, ' He claimed Ganley had agreed to pay his expenses if he became a Libertas party candidate in the 2009 Euro elections ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (323, 'Mr Lyons said it had been agreed between the parties that the settlement figure would be paid in two payments between now and the end of February together with an agreed sum towards Mr O''Malley ''s legal costs ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (324, 'He said that in the event of non-compliance with the settlement terms the defendant would consent to judgment against him ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (325, 'Judge Linnane , who adjourned the hearing briefly until the terms of settlement were lodged in the court file , put the summary judgment application back for mention on March 6 next ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (326, 'Neither party @ @ @ @ @ @ @ @ @ @ member of the Irish Farmers Association , polled 18,557 first preference votes in the East Leinster constituency and was eliminated on the third count with 19,396 votes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (327, 'Ganley , the founder and chairman of Libertas , last week received an apology and out of court settlement for defamatory comments which were made about him on the social media site , Twitter ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (328, 'Blogger Kevin Barrington stated he wished to unreservedly apologise to Declan Ganley for his tweets on 12 December 12 , 2012 and stated he had made a substantial donation to the Poor Clare Sisters ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (329, '

Syrian women far outnumber men in the refugee camps in neighboring Jordan ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (330, ' A new report by the International Rescue Committee says that gender-based violence in Syria is one of the main causes of women fleeing the country , and that reports of rape and violence against women are on the rise ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (331, ' In a clinic catering to Syrian refugees on the Jordanian border , a psychologist says she is shocked by some of the stories she hears of public rapes and torture ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (332, 'MELISSA BLOCK , HOST :') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (333, 'You are listening to ALL THINGS CONSIDERED from NPR News ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (334, 'A recent report by the International Rescue Committee sheds light on an alarming trend in Syria , a surge in sexual violence ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (335, ' Rape is a significant and disturbing feature of the Syrian war , according to the IRC report , which was based on interviews with hundreds of Syrian refugees in Jordan and Lebanon ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (336, ' The report includes the stories of a 9-year-old girl who was raped and of a father who shot his own daughter to prevent her from being , in @ @ @ @ @ @ @ @ @ @ in Jordan that provides counseling for some of these victims ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (337, ' She sent this report ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (338, 'SHEERA FRENKEL , BYLINE : In a small apartment on a nondescript street in the Jordanian city of Ramthe , Syrian refugees come to get help ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (339, ' The clinic is run by the International Rescue Committee , and it ''s a place where Syrian refugees share their stories of horror and war ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (340, 'FRENKEL : The women in the clinic asked that their identities be kept private to protect themselves and their families ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (341, ' Saher , a 42-year-old mother , comes each week with her 18-month-old baby ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (342, ' She says she fled Syria when soldiers ransacked her home and put a gun to her infant daughter ''s head ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (343, 'SAHER : ( Through Translator ) I told them there was no man in the house , so please do n''t come in ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (344, ' They pushed me down ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (345, ' I begged for mercy ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (346, ' They started to say bad words , and I began to cry ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (347, 'FRENKEL : Saher does n''t say what happened next ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (348, ' Instead , she speaks about @ @ @ @ @ @ @ @ @ @ SAHER : ( Through Translator ) Yes , there was rape , and they would even kidnap a woman if her relative is a defector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (349, ' They would take his sister or his wife ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (350, ' In Daraa , that really happened ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (351, 'FRENKEL : Nawall Mohammed is the psychologist who leads the weekly sessions with Saher and others ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (352, ' Previously , she worked with Iraqi and Palestinian refugees , but she says she ''s never heard stories that affected her as much as those from the Syrian refugees ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (353, 'NAWALL MOHAMMED : I remember a client ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (354, ' He is a man , Syrian man ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (355, ' He said the army , they collect the women , just the women and girls , and they took off their clothes and put them in big cars in the streets in front of their relatives and husbands and brothers naked ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (356, ' So it is like their weapon ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (357, 'FRENKEL : Nawall says that the women find it easier to share their stories when they can attribute them to other people ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (358, ' Some of the stories are about rape by soldiers or security @ @ @ @ @ @ @ @ @ @ that their families have suddenly become refugees ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (359, ' Melanie Megevand oversees the programs for female refugees for the International Rescue Committee ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (360, ' In the IRC ''s report , the New York-based NGO revealed that women gave sexual violence as a primary reason for fleeing Syria ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (361, 'MELANIE MEGEVAND : Given the cultural taboos , particularly in the context of the Middle East , it ''s been extremely telling to hear so many stories of sexual violence occurring and having that being explained by both men and women , including children ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (362, 'FRENKEL : Saher says that she never thought she would become a refugee , and it scares her to think about what ''s happening back in her hometown of Daraa ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (363, ' She says she ''s heard from neighbors that her home has been destroyed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (364, ' She ''s thankful that she got her family out in time ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (365, 'SAHER : ( Through Translator ) We only have our own dignity ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (366, ' A house is a minor thing , but our dignity is a basic thing ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (367, ' That ''s the reason that pushed us to come to Jordan ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (368, ' @ @ @ @ @ @ @ @ @ @ Daraa and rebuild one day ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (369, ' For now , she just wants to focus on getting better ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (370, ' For NPR News , I ''m Sheera Frenkel ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (371, 'NPR transcripts are created on a rush deadline by a contractor for NPR , and accuracy and availability may vary ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (372, ' This text may not be in its final form and may be updated or revised in the future ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (373, ' Please be aware that the authoritative record of NPR ''s programming is the audio ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (374, ' Published byStanford Medicine') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (375, 'Past studies show that maintaining strong social relationships can lower a person ''s risk for certain health conditions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (376, ' But researchers are still working to unravel the mystery about how having an active social life , or the lack of one , can influence physical health ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (377, 'Findings from two related studies recently presented at the annual meeting of the Society for Personality and Social Psychology offer new insights into how loneliness can weaken the immune system , increase sensitivity to physical pain and contribute to inflammation in the body ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (378, 'One study looked at overweight but otherwise healthy middle-aged adults , while the second evaluated breast cancer survivors ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (379, ' In both studies , participants completed stress tests , provided blood samples and had their social lives evaluated using the UCLA Loneliness Scale ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (380, 'The loneliest of the otherwise healthy participants had more markers of inflammation when tasked with a stressful activity , like speaking in front of others or doing math ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (381, 'The lonelier breast cancer survivors , in addition to increased inflammation , experienced more pain , @ @ @ @ @ @ @ @ @ @ , which tends to be triggered by stress , can also be used a measure of immune response ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (382, ' Here , those who scored higher for loneliness showed more signs of herpes reactivation ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (383, 'Researchers say the results suggest that being lonely can cause people to experience daily life as more stressful , which may cause chronic stress and in turn disrupt the immune system ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (384, 'The findings related to breast cancer survivors reminded me of research ( subscription required ) by Stanford psychiatrist David Spiegel , MD , on depression and survival rates among this group ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (385, ' Spiegel discussed his findings and the physiological connection between depression and breast cancer in this past Scope Q&A') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (386, ' The Bay Bridge') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (387, 'A SurfboardEtc ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (388, 'A Jar of Jam') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (389, 'An iPhoneAn Opera') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (390, 'The Making Of ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (391, ' The Digital El Camino Real') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (392, 'Mission Dolores , San Francisco , established 1776 on El Camino Real ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (393, 'Traverse the 600-mile trail that connects California ''s 21 missions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (394, ' Peer behind an ornate mission altarpiece that , for more than two centuries , has hidden murals painted by the Ohlone Indians ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (395, ' Uncover the mysteries of Mission Dolores '' ancient cemetery ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (396, 'CyArk , a non-profit digital scanning company based in Oakland , is creating the digital El Camino Real , documenting some of the oldest buildings and historic sites in California ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (397, 'LISTEN') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (398, 'Like Interstate 101 " Some people think the Camino Real means the Royal Road of Jesus in California , " says Andrew Galvan , curator of Mission Dolores , San Francisco ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (399, ' " No ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (400, ' It was the King ''s Highway , the King of Spain ''s highway ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (401, 'Mission Dolores , founded in 1776 , is the oldest surviving structure in San Francisco and @ @ @ @ @ @ @ @ @ @ Real to be scanned and documented by CyArk ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (402, '" If you step out the front door of Mission Dolores you are on the El Camino Real , " says Andrew ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (403, ' " It was a public road , like Interstate 101 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (404, ' All the California Missions are connected ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (405, ' Wherever you got on it , the road led you to the Viceroy ''s Palace in Mexico City ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (406, 'CyArk ''s Laser Scanning MissionCyArk has digitally preserved over 70 sites around the world from Pompeii in Italy , to Tikal in Guatemala ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (407, '" We use a 3 D laser scanner that sends out a pulsed laser beam and captures billions of points of these structures at a rate of about 100,000 points a second , " explains Elizabeth Lee who directs operations at CyArk ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (408, ' These sites are at risk , endangered due to everyday exposure to the elements , vandalism , war , urbanization , poorly managed tourism , catastrophic events , and general neglect ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (409, 'The non profit organization was founded in 2003 by Ben and Barbara Kacyra after they sold their technology @ @ @ @ @ @ @ @ @ @ imaging , mapping , modeling , and CAD system which is currently used worldwide in architecture , engineering and construction , entertainment and crime forensics ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (410, '" It was right at the time that the Bamiyam Buddhas were blown up by the Taliban , " remembers Barbara Kacyra ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (411, ' " There was no 3 dimensional documentation of them ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (412, ' We said , '' How can we use this technology to help architects , archaeologists , and preservationists get better tools than tape measures and a clip boards and a pencils to go in and document these heritage sites ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (413, 'Hidden Mural Revealed') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (414, 'Historic carved altarpiece from Mexico installed in front of mural painted by Indians ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (415, 'Sometimes new things are revealed during the scanning process ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (416, ' At Mission Dolores , CyArk worked hard to get behind the very ornately carved reredos , a false wall in back of the altar that was made in Mexico and shipped to the Mission by boat in 1796 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (417, ' For more than 200 years , the reredos has obscured a mural that was painted by the Indians when the mission @ @ @ @ @ @ @ @ @ @ a two foot space behind the frame where the statues are today , " says Andrew ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (418, ' " Very few have ever been able to see what ''s behind ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (419, ' Using fiber optics they ''ll be able to get a little pin wheel and be able to photograph ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (420, ' Then you ''ll be able to click on say Saint Joachim with your smart phone and boom ! You ''ll be able to see behind , floor to ceiling , the mural that the Indians painted here at Mission Dolores ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (421, '" It ''s not about the sites themselves , " says Barbara Kacyra , " It ''s really about the stories ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (422, ' Whether it was Manzanar or Angor Wat , or Pompeii ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (423, ' It ''s about the humanness of these sites ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (424, 'The History of San Francisco') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (425, 'There are almost 6000 Indians buried in the Mission Dolores cemetery , relates Andy Galvan , whose relationship to the Mission is much more than Museum Curator ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (426, ' Andrew is an Ohlone Indian whose ancestors were some of the first people baptized , married and buried at the Mission Dolores @ @ @ @ @ @ @ @ @ @ the gravemarkers you ''re going to read the history of San Francisco , " he says ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (427, ' " The 21 California missions are cultural heritage sites ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (428, ' These are our monuments ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (429, ' The Digital El Camino Real is about digitally imagining , about preservation ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (430, ' But it ''s also about interpretation ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (431, ' It ''s about what happened at the California Missions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (432, 'Andy Galvan ''s Ohlone Indian ancestors are buried in the cemetery at Mission Dolores ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (433, 'MORE POSTS ABOUT') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (434, 'The Making Of ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (435, ' was part of a public radio experiment called Localore -- 10 independent producers collaborating with 10 public radio stations around the nation , creating some of the new public radio programming of the future ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (436, ' During this year long collaboration we explored The Making of ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (437, ' Read More') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (438, 'Recent Posts') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (439, 'The Making Of ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (440, ' is produced by the Kitchen Sisters and KQED as part of Localore , a nationwide production of AIR , the Association of Independents in Radio with funding from the Corporation for Public Broadcasting ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (441, ' MPAA Lobbies For Army Of Hollywood Drones') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (442, 'You might not imagine the Motion Picture Association of America ( MPAA ) as a particularly drone-happy group , but new documents reveal that the actively lobbying the US government for UAV drone use in domestic space ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (443, ' No , they are n''t building an army to track down pirates ; they just want filmmakers to be able to shoot with them ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (444, 'Howard Gantman , a spokesman for the MPAA , argues that drones are safer , cheaper and easier to use for aerial shots than helicopters or cranes , and can be super useful for particularly crazy shots ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (445, ' Sure , some filmmakers are already using unmanned aerial vehicles for filming , but the legality of the issue is something of a grey area ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (446, ' The MPAA is pushing the FAA for full-on allowance of the practice so it can really " take-off " so to speak ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (447, 'The main argument against this is that widespread commercial drone use could lead to all kinds of domestic spying , a privilege the government might like to @ @ @ @ @ @ @ @ @ @ , are already working on laws to prevent exactly the sort of drone use the MPAA is lobbying for ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (448, 'Commercial drone use is a big can of worms , inside and outside of the movie industry ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (449, ' Currently , the FAA plans on starting to issue private drone licences by 2015 , but it still has to work out the details of who should be allowed to get them ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (450, ' If the MPAA has anything to say about it , filmmakers will definitely be on that list ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (451, ' While they ''re at it , maybe they could put in a good word for fast-food delivery drones too ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (452, ' The Hill via Fast Company') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (453, 'Just because there is a picture of a Predator ( or similar ) in the story does n''t mean that the studios want military drones ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (454, ' These beasts are not necessarily cheap nor efficient for what they want ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (455, ' ( Though they Do have a lower hourly rate than a Cessna or Jetranger , but their purchase cost is higher ( Typically POA ) than a small GA fixed wing ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (456, ' ( More in the @ @ @ @ @ @ @ @ @ @ Just an RC plane used for commercial purposes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (457, 'The name drone actually means a dumb worker ( as in drone bee ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (458, 'People somehow have only associated the word with semi-autonomous killer drones ( which are actually usually manually piloted , which is why they tend to crash all the time ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (459, ' ( let the computer do the flying and all will be fine ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (460, 'The USA has pretty restrictive laws on flying uninhabited aircraft ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (461, ' ( as did most of the rest of the world ) generally it is only legal to fly these beauties ( big or small ) for hobby purposes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (462, 'In Australia , if the aircraft is : Away from residential areas , Below 400 feet above the ground ( yep I know that is fairly low ) Within eyesight of the operator Under 150 kg weight ( but getting clearance from the MAAA for over 50kg is a bit hard )') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (463, 'There are NO rules ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (464, ' BUT ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (465, 'Your Insurance company is unlikely to offer cover , therefore actually having a viable business using such craft @ @ @ @ @ @ @ @ @ @ )') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (466, 'Also , putting professional cameras on a Quad , it will need to be a fairly large quad , and the batteries will sort of run out pretty quick ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (467, ' Better using a 4m fixed wing or 3 metre heli ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (468, '( If the above rules are met , there is no regulation in Australia ( Check out the CASA website , they say it in as few words ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (469, 'But if you want to operate outside these regulations , you need to jump through lots of hoops ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (470, 'Trending Stories Right Now') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (471, 'My initial reaction to Apple ''s expensive new iPhone battery case was in step with the everyone else ''s ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (472, ' It looks like it has a tumour ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (473, ' But what I discovered after using it for a full day is it ''s actually surprisingly great ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (474, 'You might ''ve seen Zaha Hadid ''s name in the news after Japan ''s Sports Council announced a design to her replace her widely loathed and alien-like Olympic stadium in Tokyo ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (475, ' But the real update comes in the form of a new skyscraper in @ @ @ @ @ @ @ @ @ @ earplug ?') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (476, 'The droids in the Star Wars universe often play a key role in the movies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (477, ' But how close are they to some of the real robots in our own universe ? Professor Jonathan Roberts from the Queensland University of Technology drops his science on those assembled ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (478, ' Mum ''s fight over dog mess on pavements') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (479, 'Get daily news by email') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (480, 'Invalid e-mailThanks for subscribing ! Could not subscribe , try again later') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (481, 'Mary Patel') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (482, 'A frustrated mum is on a one-woman mission to stop dogs littering the streets -- by spray-painting their mess ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (483, 'Mary Patel , 33 , has been scouring the pavements of Gorse Hill in Stretford to highlight the problem by spraying dog muck with biodegradable yellow paint ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (484, 'Mary believes the problem is out of control on the streets and in parks , and is determined to do something about it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (485, 'The mum-of-one said : " I ''ve lived in Gorse Hill for seven years and I really like the area ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (486, ' Lots of kids play out in the street but they ''re having to play among the dog poo ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (487, ' I have a 10-month-old baby , Elsie , and in the future I want her to be able to go to the park and walk along the street without swerving the mess ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (488, 'Mary came up with the idea @ @ @ @ @ @ @ @ @ @ up , then spent weeks searching for biodegradable paint ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (489, 'So far she has painted 30 piles of waste and intends to keep up her canine campaign ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (490, 'She added : " I want other people to see it where it is so we can try to say to dog owners , '' we do notice , people are frustrated by it '' ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (491, 'Peter Molyneux , from Trafford council , said : ? " The council is aware of specific problems in the Gorse Hill area and have patrols out targeting the area in an effort to crack down on the perpetrators of this anti-social behaviour ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (492, 'Our newspapers include the flagship Manchester Evening News - Britain ''s largest circulating regional daily with up to 130,485 copies - as well as 20 local weekly titles across Greater Manchester , Cheshire and Lancashire ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (493, 'Free morning newspaper , The Metro , published every weekday , is also part of our portfolio , delivering more than 200,000 readers in Greater Manchester ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (494, 'Greater Manchester Business Week is the region ''s number one provider of @ @ @ @ @ @ @ @ @ @ 12,687 copies every Thursday ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (495, 'Every month , M') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (496, ' Media ''s print products reach 2') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (497, '2 million adults , spanning from Accrington in the north to Macclesfield in the south ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (498, ' IPPC to investigate case of autistic teenager arrested by Merseyside police officers who assumed she was drunk') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (499, 'MERSEYSIDE police will be investigated after officers mistakenly arrested an autistic teenage girl for being drunk ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (500, 'Shares') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (501, 'Get daily news by email') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (502, 'Invalid e-mailThanks for subscribing ! Could not subscribe , try again later') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (503, 'IPPC to investigate case of autistic teenager arrested by Merseyside police officers who assumed she was drunk') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (504, 'MERSEYSIDE police will be investigated after officers mistakenly arrested an autistic teenage girl for being drunk ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (505, 'Melissa Jones , 17 , was charged with being drunk and disorderly despite suffering with communication problems as part of her condition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (506, 'Merseyside police has referred the matter to the Independent Police Complaints Commission ( IPCC ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (507, 'The force said it would also look into the handing of the case ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (508, 'A spokesman said it would be reviewing the case to see " if there are any lessons to be learned " ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (509, 'College student Melissa , who was 16 at the time , spent the night in @ @ @ @ @ @ @ @ @ @ DNA taken after she intervened in a brawl in which she ended up being assaulted ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (510, 'Police issued Melissa with a fixed penalty notice , but she appealed against it and appeared before court in November last year , where she was formally charged with being drunk and disorderly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (511, 'A trial was due to be held next month , but Melissa was told last week that the CPS were dropping the case due to " insufficient evidence " ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (512, 'Her mum , Christine Evans , 49 , told the ECHO : " She should never have been arrested in the first place , let alone charged with drunk and disorderly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (513, '" She was upset after being beaten up , so when the police arrested her she became hysterical because she knew she had n''t done anything wrong ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (514, 'Melissa had been to a shop with friends , near her home in Wavertree , shortly before midnight on June 16 last year , to buy soft drinks ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (515, 'A drunken woman entered the shop , in Smithdown Road , and became aggressive when @ @ @ @ @ @ @ @ @ @ her friends were attacked when they tried to intervene ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (516, ' Both girls were stamped on and suffered severe bruising ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (517, 'Christine said : " This woman had been kicking another girl in the head ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (518, ' Melissa thought she was going to kill her , so she jumped in and the woman turned on her ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (519, '" I ran to the shop and told the police Melissa had n''t touched a drop -- she ''s a good girl , but her autism means she ca n''t communicate the way we do ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (520, 'Christine said Melissa ''s ordeal with the police and going to court had affected her daughter so badly she has needed counselling ever since ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (521, 'She added : " Melissa has been through hell for the last six months , she ''s even tried to kill herself over this ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (522, 'A Merseyside Police spokesman said : " A 16- year-old girl was arrested on suspicion of being drunk and disorderly following a disturbance in a shop ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (523, ' She was taken to a police station , examined by a doctor , and interviewed when @ @ @ @ @ @ @ @ @ @ and released ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (524, '" The Crown Prosecution Service later made a decision not to continue with the case ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (525, 'Send a story') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (526, 'Advertising Department') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (527, 'Trinity Mirror Merseyside , the Echo ''s parent company , is one of the North West ''s largest multimedia providers reaching more than 900,000 adults every month ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (528, 'The Liverpool Echo , Trinity Mirror Merseyside ''s flagship brand , is the area ''s best-read newspaper including national newspapers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (529, 'The Liverpool Echo reaches 1 in 3 people in the area with a daily readership of more than 256,000* people') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (530, 'The Liverpool Echo website reaches 1') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (531, '5 million unique users each month who look at around 8') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (532, '5 million pages** ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (533, 'The Editor') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (534, 'Alastair Machray') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (535, 'Alastair Machray was appointed editor of The Liverpool Echo in 2005 and is also editor-in-chief of Trinity Mirror Merseyside , Cheshire and North Wales ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (536, ' He is a former editor of The Daily Post ( Wales and England ) and editor-in-chief of the company ''s Welsh operations ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (537, ' Married dad-of-two and keen golfer Alastair is one of the longest-serving newspaper editors in the country ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (538, ' His @ @ @ @ @ @ @ @ @ @ ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (539, '

North America ''s population in the 19th century spread from east to west , driven in the main by farming ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (540, ' And where farmers planted themselves , so grew a demand for farm credit , and eastern bankers followed them ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (541, 'Drought and crop failure repeatedly parched farmers '' credit , and their bankers '' , and when fresh credit got tough to get , the farmers turned to government for help ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (542, ' Here , farm economics and politics led to the 1920s '' Canadian Farm Loan Board , created to offer mortgages to respond to a perceived lack of credit for Western farmers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (543, 'The Farm Credit Corporation replaced the board in 1959 , with a broader mandate that included consulting services for farmers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (544, ' The former board operated mostly on a for-profit basis , but FCC ''s lending rate was set at 5% , well below profitability , amounting to an interest rate subsidy to farmers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (545, ' By the 1970s , as the corporation ''s losses mounted , interest rates were set at " the cost of funds plus 1') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (546, '@ @ @ @ @ @ @ @ @ @ Farm Credit Corporation Act ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (547, ' The new Act allowed FCC to finance farm-related enterprises , and bigger farms ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (548, ' It did not limit FCCs activities to filling gaps left by the private sector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (549, ' These steps -- the shift from for-profit to subsidized farm credit , and the expansion to areas where there was no clear market failure -- signaled departure from FCC ''s original credit-gap mandate ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (550, ' Changes in 2001 allowed FCC to offer more of financial and business management services , and widened FCC ''s potential clientele to include more farm-related businesses , including those not farmer-owned ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (551, ' And FCC has seen tremendous growth : Its share of farm debt grew from about 14% in 1992 to 29% by the end of 2011 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (552, 'FCC ''s share of farm debt stands against that of all chartered banks , which hold 36% , and all credit unions , which hold another 16% ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (553, ' FCC has expanded its activities , enlarged its capital base to do so , and built market in a field where the private sector is historically competitive ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (554, 'FCC ''s success owes much to its @ @ @ @ @ @ @ @ @ @ government , and it borrows directly from the federal government on terms that reflect Ottawa ''s credit quality ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (555, ' It does not face the same regulatory capital requirements as other financial institutions , and pays no corporate income tax ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (556, ' And FCC ''s loan offerings and terms are different from others '' ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (557, ' FCC loans tend to have long amortization periods , higher loan-to-value ratios , and the corporation stands at least as ready as others to lend against supply management ( dairy and poultry farm ) quotas and to offer interest-only loans ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (558, ' It finances farmers who sign Ontario " green energy " supply contacts ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (559, ' Other offerings seem likely to encourage debt and inflate farm asset values :') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (560, 'The Capacity Builder Loan , to finance quota purchases or livestock , with an option to capitalize interest ( in turn , deeply investing FCC , and federal taxpayers , in maintaining the farm quota system ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (561, 'None of these is inherently inappropriate , but they are risky , in much the same way that so-called subprime mortgage lending is risky ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (562, ' Loans characterized by low down payments @ @ @ @ @ @ @ @ @ @ early accumulations of interest due , or involve balloon or variable future payments , have a higher default rate than more traditional loans ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (563, 'Now , lending under such risky conditions carries an interest rate premium ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (564, ' For small business lending , a typical risk premium might be 300 basis points above prime ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (565, ' Of course , FCC does not charge such a premium and , unsurprisingly , its relatively risky loan books carry an impairment ratio that exceeds its competitors '' ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (566, ' And risks have been growing alongside farm indebtedness as a percent of net income ( see graph ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (567, 'The implications are simple but serious : FCC competes with private-sector lenders in offering financing services to farmers and others ; its market share has been growing without a regulatory capital constraint ; and farm lending has grown relative to farm income , an indicator of rising risk in the sector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (568, ' The increased financial risks also appear on the asset side of farms '' balance sheets ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (569, ' The values of farms and buildings , and farm quota values , have shown effervescent increases in recent years @ @ @ @ @ @ @ @ @ @ '' total assets ( see graph ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (570, ' And FCC ''s lending has grown even faster than farm asset values ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (571, 'Of course , credit tends to drive asset prices , and increases tend to be followed by sharp revaluations ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (572, ' Recent farm debt growth , coupled with FCC ''s aggressive strategies , warrants closer examination by regulators and taxpayers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (573, ' The potential impacts are not only related to FCC : Its market pressure pushes private lenders to adjust their own lending standards , to remain competitive ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (574, 'Canadian regulators need to monitor the situation more closely ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (575, ' FCC , as is the case for the BDC and EDC , is not formally subject to a prudential regulator ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (576, ' As a starting place , FCC should be brought under OSFI supervision ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (577, 'Letters to the editor') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (578, 'Please include your address and daytime telephone number ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (579, ' We give preference to letters that refer to a particular article by headline , author and date ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (580, 'If your letter concerns articles in other sections of the National Post , including business articles that appear in the A section , @ @ @ @ @ @ @ @ @ @ and other materials sent to the publisher and accepted for publication remains with the author , but the publisher and its licensees may freely reproduce them in print , electronic and other forms ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (581, ' James Fergusson : Up in the air , North of 60') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (582, 'Up in the air , North of 60') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (583, 'What follows is the third of five excerpts from a newly released e-book , The Canadian Forces in 2025 : Problems and Prospects ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (584, ' The publication was commissioned by the Strategic Studies Working Group -- a partnership between the Canadian International Council and the Canadian Defence and Foreign Affairs Institute ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (585, ' In today ''s installment , James Fergusson looks at our Air-Force presence in the Arctic ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (586, 'The federal government has tasked the Canadian Forces with monitoring , controlling and enforcing Canadian laws and regulations over its Arctic territory and adjacent waters ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (587, ' In so doing , the government , through its 2008 Canada First Defence Strategy and National Shipbuilding Strategy , has focused particular attention on the Royal Canadian Navy ( RCN ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (588, 'The RCN and Coast Guard will play a major role in enforcing national laws and regulations on fishing , the environment , shipping and smuggling ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (589, ' However , the major burden will fall on the Royal Canadian Air Force @ @ @ @ @ @ @ @ @ @') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (590, 'Today , the RCAF is a " southern , " overseas Air Force that goes North only when necessary ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (591, ' Only four Twin Otter aircraft are permanently deployed to the North , at Yellowknife , with Joint Task Force North Headquarters ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (592, ' They undertake a variety of missions , including search and rescue ( SAR ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (593, 'A small number of CF-18 fighters , deployed at Cold Lake and Bagotville , and assigned to NORAD , are dedicated to the air-sovereignty mission ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (594, ' Their primary use continues to be to intercept Russian bombers on training missions as they approach Canadian air space ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (595, ' Four forward operating locations ( FOLs ) , co-located with civilian airports in Yellowknife , Inuvik , Iqaluit and Rankin Inlet were developed in the 1980s for the dispersal of CF-18s to the North ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (596, ' In addition , the Aurora surveillance and reconnaissance aircraft undertake regular Arctic patrols ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (597, 'To monitor Canadian and North American air space in the North , the North Warning System ( NWS ) replaced NORAD ''s Distant Early Warning radar line in the 1980s ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (598, ' It primarily consists of automated @ @ @ @ @ @ @ @ @ @ the Northwest Passage ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (599, ' Finally , the RCAF operates Canadian Forces Station Alert on the northern tip of Ellesmere Island ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (600, ' The station performs a signals intelligence function and supports SAR ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (601, 'It is projected that over the next decade there will be an exponential increase in shipping and resource exploitation activity in the Arctic ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (602, ' If so , the RCAF will be required to monitor Canada ''s Arctic on a daily basis ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (603, ' More activity also means an increase in search and rescue demands ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (604, ' As such , the RCAF will have no choice but to shift resources to the North on a permanent basis ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (605, 'To meet this demand , the existing FOLs likely will become permanent bases for forward deployed surveillance and reconnaissance and SAR aircraft ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (606, ' The Aurora , or possibly future unmanned aerial vehicles ( UAVs ) , will play a vital role in monitoring traffic over this expansive area ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (607, ' Though UAVs can be operated from bases in the south through satellite links , they will still need to be maintained at their bases in the North ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (608, 'Being cued by the @ @ @ @ @ @ @ @ @ @ will provide tracking of shipping and fishing vessels , the identification of targets of interest , and direction of RCN or Coast Guard vessels for interception purposes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (609, ' Permanently deployed SAR aircraft and helicopters will be necessary to provide rapid response to accidents in the North ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (610, ' In addition , helicopters also will potentially provide a rapid response interception capability ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (611, 'There is also a slight possibility that the CF-18 or its replacement will need to be permanently deployed to the North ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (612, ' However , the likelihood that significant military threats will emerge in the Arctic is very low , especially as a function of the harsh environment ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (613, 'Finally , the North Warning System will likely be expanded northward as part of its future modernization , with all the attendant costs of building new sites ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (614, 'Currently , the RCAF is developing a northern plan to meet future demand ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (615, ' Regardless of the details , the costs will be significant ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (616, ' Building and staffing permanent bases will be expensive , although some costs may be offset by other government departments and agencies in response to increased civilian @ @ @ @ @ @ @ @ @ @ no need to acquire a dedicated Arctic aircraft : The current and planned inventory of multi-role aircraft will be able to meet this requirement ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (617, ' That will reduce some costs ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (618, ' However , aircraft and personnel deployed to the North on a permanent basis will impact the ability of the RCAF to meet its other demands ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (619, 'Costs related to the retention and recruitment of personnel also will be significant ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (620, ' Canadians may have an emotional attachment to the North , but this does not necessarily mean that RCAF personnel and their families will look forward to being posted there for several years ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (621, 'In order to meet these costs , the key issue for the RCAF is whether government will be willing to provide the necessary funding ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (622, ' If not , the RCAF will be strained to the breaking point , which will cascade throughout the organization as it confronts other significant investment demands on its equipment and personnel ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (623, 'National Post') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (624, 'James Fergusson is a Research Fellow with the Canadian Defence and Foreign Affairs Institute ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (625, ' From Richard III to Johnny Rotten : The changing face of evil Add to ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (626, 'When Johnny Lydon , then known as Johnny Rotten , took the microphone in front of the Sex Pistols in the late 1970s , he projected a fantastic malevolence ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (627, ' Skinny , hunched , wide-eyed , a man anger-obsessed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (628, ' He also began to affect a strange accent , a hyper-enunciation , with trilled r ''s ( as in " Rrright , now " ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (629, ' It was clearly his own Cockney tinged with something else , a parody of something aristocratic ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (630, ' Lydon has said in interviews , and in his autobiography , that this stage persona was partly inspired by Laurence Olivier ''s performance of Richard III , in his 1955 film based on the Shakespeare play ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (631, 'And indeed that is the image -- the twisted , poetic man with murder on his mind -- that we have long had imprinted on us , an image not just of this particular king but of English kings in general ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (632, ' It was a creation of Shakespeare and of @ @ @ @ @ @ @ @ @ @ Sex Pistols but by Rowan Atkinson in the early Blackadder episodes and even to a certain extent by Jonathan Rhys Meyers as a slender yet savage Henry VIII in The Tudors ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (633, ' It informed Heath Ledger ''s nastily disfigured Joker character ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (634, 'Disfigurement -- or simple ugliness -- is key to the persona in all its iterations ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (635, ' Shakespeare called the king a hunchback ( we now know he had severe scoliosis ) ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (636, ' He was using a crude and ancient trick of storytelling : Villains , like monsters , are ugly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (637, ' They bear some deformity that evinces their evil ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (638, ' The monster Grendel , Beowulf ''s nemesis , is an " unnatural birth , " larger than a man , his skin covered in a horny iron substance ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (639, ' Rumpelstiltskin , the evil imp , is the opposite : a dwarf ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (640, ' Witches and wicked stepmothers have warts and curved noses throughout fairy tales ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (641, ' The tradition continues through modern science fiction , where alien enemies are usually reptilian , or masked , like Darth Vader -- what horrible visage is the dark lord protecting from sight ? @ @ @ @ @ @ @ @ @ @ Rotten was using to command attention : Ugliness is clever , rebellious , angry ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (642, ' His ugliness heralded revolution ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (643, ' And Shakespeare ''s Richard III is similarly complex : His resentment about his deformity motivates him ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (644, ' Some of the most frightening lines about physical ugliness in English literature come out of his mouth : Deformed , unfinish ''d , sent before my time / Into this breathing world , scarce half made up , And that so lamely and unfashionable / That dogs bark at me as I halt by them ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (645, ' " Later Queen Margaret describes him as a " poisonous bunchback ''d toad ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (646, ' " ( He calls her in return a " hateful wither ''d hag ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (647, ' " Shakespeare did not fear causing offence ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (648, 'It is hard for anyone with a disability or deformity to read those lines ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (649, ' I have a minor one myself ( funny hands ) and remember being moved , as a teenager reading this play , by the horror of the dogs as the lame man passes by ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (650, 'In modern times , interpreters of Shakespeare ''s character @ @ @ @ @ @ @ @ @ @ ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (651, ' A famous Royal Shakespeare Company show from 1984 had actor Richard Sher playing the king in crutches , barely able to walk ; other companies have used actors with real disabilities to play the king , including at least one in a wheelchair ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (652, ' The idea , with every new version of the play , is to add to the character ''s complexity , to make him more than a mere psycho ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (653, 'By the 19th century , the sentimental archetype of the deformed antihero had shifted to a more benevolent one ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (654, ' Quasimodo , the hunchback of Notre Dame , is an object of sympathy rather than loathing ; a simple victim rather than a complex tyrant ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (655, ' This is now a convention we are familiar with too , in theatre in particular -- The Phantom of the Opera is also about a disfigured face that needs love ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (656, 'Even in recent science fiction and fantasy , attempts have been made to break negative expectations of abnormal-looking characters ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (657, ' Tyrion Lannister , the manipulative genius of Game of Thrones , is a sympathetic dwarf , and as @ @ @ @ @ @ @ @ @ @ has become a sex symbol ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (658, ' The South African sci-fi film District 9 created a slave race of slimy aliens -- they have tentacles on their faces and are rudely called Prawns -- who are the most sympathetic , and secretly intelligent , characters in the story ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (659, ' The idea in modern representations is that we the audience all feel abnormal in some way and are going to identify with the mocked and shunned far more than with the powerful ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (660, ' This idea of individualism is a recent one , a product of the Enlightenment and Romanticism ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (661, 'Shakespeare ''s textured and interesting Richard III , though , is part of the beginning of that transformation , for disfigured characters in literary history , from monsters to charming victims or even stoic heroes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (662, ' Richard , like Johnny Rotten , is dissatisfied with " idle pleasures , " and " determined to be a villain , " and an amusing and charming villain he is ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (663, ' This was around 1592 -- 75 years before Milton ''s attractively tortured Satan , in Paradise Lost , became a model for sexy villains @ @ @ @ @ @ @ @ @ @ found evidence that the real Richard III was not only actually deformed but that his life of battle was truly an ugly one ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (664, ' The skeleton found under a parking lot in Leicester showed the results of bound wrists , an axe or sword blow to the head , a sword through the buttocks , and other unnamed " humiliation wounds , " probably inflicted after death ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (665, ' This king was torn apart by a mob of soldiers , his body publicly defiled and then thrown into an unmarked grave ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (666, ' The world of violence these guys lived in was ruthless from birth ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (667, ' One ca n''t really imagine a blameless moral king coming out of this culture ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (668, ' Plantagenets , Tudors , Sopranos -- all fundamentally depraved family sagas ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (669, ' We need a scary character -- a face -- to embody the blood thirst of the time ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (670, 'Creepily , a computer reconstruction of Richard III ''s face , based on the skull recently dug up , bears a very slight resemblance to the young Laurence Olivier''s') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (671, ' '' Incompatible with life '' : Mother ''s account of her difficult decision to request a late-term abortion sheds light on '' live-born '' debate') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (672, 'One mother ''s account of her difficult decision to request a rare , late-term abortion') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (673, 'Twenty-one weeks into her second pregnancy , when the fetus was diagnosed with a rare bone disease , Carol determined she had two options : Miscarry the baby naturally and deliver a child with a shattered skeleton that would live for a matter of seconds or request a rare late-term abortion ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (674, '" I found out when I was five months pregnant , and ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (675, ' by the time you ''re five months pregnant you ''re all in , " said Carol , not her real name ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (676, ' " There ''s no great outcome in these situations ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (677, 'Babies without lungs , kidneys , spines , bones or brains : These are the rare " incompatible with life " conditions that clinicians say prompt most , if not all , of Canada ''s contentious " live born " abortions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (678, ' According to Statistics @ @ @ @ @ @ @ @ @ @ and 2009 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (679, 'But while three MPs drafted a Jan') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (680, ' 23 letter to the RCMP citing these " live born " abortions as evidence of premeditated " homicide " in Canadian hospitals , clinicians and veterans of the procedure maintain that in Canada , the only fetuses terminated in late-stage abortions are those whose fates are already sealed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (681, 'Carol ''s fetus was killed by the procedure , but it was virtually identical to those that result in live births ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (682, '" I want people to understand what these women have been through before they start accusing the doctors who helped them of being murderers , " said Carol ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (683, 'In 2010 , 537 Canadian women underwent abortions after 21 weeks of pregnancy , not including Quebec ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (684, ' According to Wendy Norman , a clinical professor at the University of British Columbia , " almost everyone " in those cases " has some different anomaly ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (685, 'Some have fetal anencephaly , a condition in which the fetus fails to develop a brain ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (686, 'Others fail to develop kidneys , a condition known as Potter @ @ @ @ @ @ @ @ @ @') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (687, 'Many times , said Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (688, ' Norman , the specific defect is so rare that it does not even have a proper medical name ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (689, 'After an ultrasound at 21 weeks , Carol ''s fetus was diagnosed with osteogenesis imperfecta , a genetic disorder that results in severe bone fragility ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (690, 'Less severe condition are survivable , although they result in physical deformities into adulthood ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (691, ' Carol ''s fetus , however , had one of the most extreme cases ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (692, 'If the baby was naturally stillborn , said Carol , she would have needed to select a name , learn the child ''s gender and make funeral arrangements ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (693, 'Carol requested a late-stage abortion , adding that the procedure was never broached by medical staff , and even finding a physician qualified to perform it was a challenge ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (694, '" They ''re not offering these things up ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (695, ' It was n''t even presented as an option , " she said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (696, 'If anything , she said , hospital staff made sure to explain why some women will carry a known stillborn to @ @ @ @ @ @ @ @ @ @ birth ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (697, 'Blogs and online pregnancy forums abound with testimonials from women who carried their children to term with full knowledge that they would not live more than a matter of minutes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (698, 'I savored every kick and turn she made inside my growing belly') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (699, '" I savored every kick and turn she made inside my growing belly , " wrote one woman of her decision to carry a fetus with fetal anencephaly to term ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (700, 'Wrote another woman whose fetus was diagnosed with Potter ''s Syndrome , " I chose to carry to term and made it to 37 1/2 weeks when we had a C-section ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (701, ' He lived just under three hours , the happiest and saddest hours of my life ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (702, 'Speaking to the Post in November , Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (703, ' Douglas Black , president of the Society of Obstetricians and Gynaecologists , speculated that similar sentiments may underlie the 491 " live-born " abortions between 2000 and 2009 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (704, 'As hospitals will routinely administer a lethal injection to a fetus prior to a later-stage abortion , Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (705, ' Black guessed that any aborted @ @ @ @ @ @ @ @ @ @ due to the " private choice " of a mother ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (706, 'Such fetuses are " subsequently allowed to pass away , depending on what the circumstances are , sometimes in their mom ''s arms , " he said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (707, 'For Carol , there were physical risks of carrying the fetus to term over another four months , but she said it was also a psychological decision ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (708, '" The idea of having the pain of childbirth compounded by the really emotional trauma of losing a child , it was a lot to take on ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (709, ' I do n''t think I would have been able to think about having more babies subsequently , " she said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (710, ' She has since given birth to a second child in a complications-free pregnancy ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (711, ' Mary Leakey , the '' grande dame of archeology , '' gets a Google celebration for her 100th birthday') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (712, 'Mary Leakey , the '' grande dame of archeology , '' turns 100') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (713, 'Mary Leakey cemented her status as a giant of archeology in 1959 with one confident cry : " I ''ve found him -- I ''ve found our man ! "') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (714, 'She was calling out to her husband , Louis , after coming across a bone protruding from stones during an expedition in Tanzania ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (715, ' " Her man " was an Australopithecus boisei ape -- about 1') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (716, '8 million years old ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (717, ' His was the first fossilized skull ever found from the extinct , human-related species ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (718, 'Leakey , the " grande dame of archeology , " as author Virginia Morrell put it , would have turned 100 Wednesday ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (719, ' To mark the occasion , Google converted its logo into a tribute to the British archaeologist ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (720, 'The Australopithecus boisei skull was one of several important discoveries Leakey made in her career -- all made despite the fact that she had nearly @ @ @ @ @ @ @ @ @ @ She got thrown out of school very early on and never wanted to go back , and became hugely interested in archaeology , " Richard Leakey , her son , told Archaeology magazine') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (721, 'She had been working as an illustrator for archeological books , which was how she met her eventual husband , archeologist Louis Leakey ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (722, 'In their time working together , the couple made significant discoveries in the field , including uncovering the Homo habili " handy man " and , later , the Laetoli Footprints -- which showed human-like walking patterns from 3') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (723, '6 million years ago ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (724, 'Leakey died in 1996 at the age of 83 ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (725, ' " She was one of the world ''s great originals , " anatomist Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (726, ' Alan Walker , who had accompanied the Leakey family on expeditions , told the New York Times for her obituary ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (727, 'She was one of the world ''s great originals') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (728, '" Untrained except in art , she developed techniques of excavation and descriptive archeology and did it all on her own in the middle of Africa , " he added ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (729, ' " @ @ @ @ @ @ @ @ @ @ death , her family name is still making headlines in the world of archeology ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (730, ' Just a few months ago , Meave Leakey , Mary ''s daughter-in-law , made news after her team reported finding a new species of humans from two million years ago ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (731, 'To honour Mary ''s 100th birthday , the Leakey Foundation is encouraging people to donate $100 in her honour to further scientific knowledge of human origins ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (732, ' Indian Railway ''s total earning up by 20%') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (733, 'The total approximate earnings of Indian Railways on originating basis during 1st April 2012 to 31st January 2013 was Rs 101223') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (734, '95 crore compared to Rs 84083') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (735, '74 crore during the same period last year ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (736, 'TNN Feb 11 , 2013 , 03') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (737, '34 PM IST') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (738, 'MUMBAI : The total approximate earnings of Indian Railways on originating basis during 1st April 2012 to 31st January 2013 was Rs 101223') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (739, '95 crore compared to Rs 84083') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (740, '74 crore during the same period last year , registering an increase of 20') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (741, '38 per cent ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (742, 'A press release issued by the ministry of railways said , " The total goods earnings have gone up from Rs 56163') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (743, '30 crore during 1st April 2011 - 31st January 2012 to Rs 70067') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (744, '36 crore during 1st April 2012 - 31st January 2013 , registering an increase of 24') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (745, '76 per cent ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (746, 'The total passenger revenue earnings during 1st April 2012 - 31st January 2013 was Rs 25924') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (747, '29 crore compared to Rs') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (748, ' 23344') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (749, '42 crore during the same period last year , registering an increase of 11') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (750, '05 @ @ @ @ @ @ @ @ @ @ The revenue earnings from other coaching amounted to Rs 2617') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (751, '19 crore during April 2012 - January 2013 compared to Rs 2353') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (752, '54 crore during the same period last year , an increase of 11') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (753, '20 per cent ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (754, 'The total approximate numbers of passengers booked during 1st April 2012 - 31st January 2013 were 7150') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (755, '60 million compared to 6910') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (756, '00 million during the same period last year , showing an increase of 3') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (757, '48 per cent ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (758, 'The ministry further said in the suburban and non-suburban sectors , the numbers of passengers booked during April 2012 -January 2013 were 3753') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (759, '32 million and 3397') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (760, '28 million compared to 3651') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (761, '70 million and 3258') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (762, '30 million during the same period last year , showing an increase of 2') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (763, '78 per cent 3') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (764, '48 per cent respectively ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (765, 'RELATED') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (766, 'From around the web') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (767, 'More from The Times of India') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (768, 'Recommended By Colombia') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (769, 'From Around the Web') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (770, 'More From The Times of India') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (771, 'Recommended By Colombia') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (772, 'Comments') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (773, 'Characters Remaining : 3000') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (774, 'OR PROCEED WITHOUT REGISTRATION') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (775, 'Share on Twitter') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (776, 'SIGN IN WITH') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (777, 'FacebookGoogleEmail') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (778, 'Refrain from posting comments that @ @ @ @ @ @ @ @ @ @ indulge in personal attacks , name calling or inciting hatred against any community ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (779, ' Help us delete comments that do not follow these guidelines by marking them offensive ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (780, ' Let ''s work together to keep the conversation civil ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (781, 'Read more') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (782, 'Most Popular') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (783, 'The external affairs ministry on Wednesday advised Indian students seeking admission in two California-based universities to defer their departure till it gets a response from the US government on the issue ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (784, ' News You Can Use 24 genes enhance the risk of myopia') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (785, 'An unfavourable combination of genetic predisposition and environmental factors appears to be particularly risky for the development of myopia ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (786, 'Scientists have identified 24 new genes that cause myopia or short-sightedness , a breakthrough that could lead to drugs for prevention of the eye condition from which 80% of Asians suffer ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (787, 'Myopia is a major cause of blindness and visual impairment worldwide , and currently there is no cure , according to a study published in the journal Nature Genetics ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (788, ' The study was led by professor Chris Hammond from the department of twin research and genetic epidemiology at King ''s College London ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (789, ' Researchers analysed the genetic and refractive error data of over 45,000 people from 32 different studies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (790, ' The new genes include those which function in brain and eye tissue signalling , the structure of the eye , and eye development ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (791, ' It was already known that environmental factors , such as reading , lack of outdoor exposure , and a higher level of education can increase the risk @ @ @ @ @ @ @ @ @ @ environmental factors appears to be particularly risky for the development of myopia ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (792, '" This study reveals for the first time a group of new genes that are associated with myopia and that carriers of some of these genes have a tenfold increased risk of developing the condition , " Prof') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (793, ' Hammond said in a statement ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (794, ' Banks can open A/cs for Bangladeshi nationals sans RBI nod') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (795, 'MUMBAI : The Reserve Bank today said banks are permitted to now open non-resident ordinary rupee ( NRO ) account of Bangladeshi nationals without its prior approval ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (796, ' it has been decided that henceforth , banks would be permitted to open NRO account of individual/s of Bangladesh nationality without the approval of the Reserve Bank , " it said in a notification ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (797, 'The permission is granted subject to the conditions the bank should satisfy itself that the individual holds a valid visa and valid residential permit ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (798, 'The RBI said banks should put in place a system of quarterly reporting whereby each branch of the bank shall maintain a record of the bank accounts opened by individual(s) of Bangladesh nationality and details of such account shall be forwarded to their head office ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (799, 'The head office of the concerned bank shall furnish details of such accounts --containing the name , date of arrival in India , passport number , residential permit reference , name of the Foreigner Registration Office @ @ @ @ @ @ @ @ @ @ the bank branch where the account is maintained -- on quarterly basis to the Ministry of Home Affairs ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (800, 'However , opening of accounts by entities of Bangladesh ownership shall continue to require approval of RBI , it added further ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (801, 'As per the extant guidelines , opening of Non-Resident Ordinary Rupee ( NRO ) accounts by individuals/entities of Bangladesh/Pakistan nationality/ ownership requires approval of Reserve Bank ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (802, ' Tell the dogs something they have n''t known all along') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (803, 'Here ''s the answer : Of course you do ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (804, ' All dog owners , in their heart of hearts , are convinced their drooling pet is the canine version of Einstein , only with better grooming ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (805, 'GUS RUELAS / PURINA / THE ASSOCIATED PRESS ARCHIVES') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (806, 'Cochiti , a six-year-old whippet , competes in a diving dog competition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (807, ' A new book argues dogs are smarter than you think ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (808, 'Stray dogs in Moscow are smart enough to use public transport , a fact accepted by Muscovites who do n''t crowd them on the subway ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (809, 'The thing is , they ''re right : dogs are geniuses ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (810, 'In this well-researched , highly readable book , author Brian Hare -- a scientist who is becoming known throughout the world as " that dog guy " -- has laid out a compelling argument for the unique genius of man ''s best friend ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (811, 'It ''s not that your dog has the skill to paint a masterpiece or compose a @ @ @ @ @ @ @ @ @ @ a special kind of intelligence that gives them more in common with human infants than their wolf ancestors ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (812, 'Written with his co-researcher and wife , Vanessa Woods , The Genius of Dogs is the first book to provide a complete look at the new world of " dog cognition , " which has been playfully dubbed " dognition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (813, 'For hundreds of years , researchers largely overlooked the millions of domesticated dogs that serve as pets or service animals , comfortably working alongside humans ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (814, 'But in the last 10 years , there has been something of a revolution in the study of canine intelligence , and Hare has been the scientist leading the charge ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (815, '" We have learned more about how dogs think in the past decade than we have in the previous century , " Hare writes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (816, ' " This book is about how cognitive science has come to understand the genius of dogs through experimental games using nothing much more high-tech than toys , cups , balls and anything else lying around the garage ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (817, 'An evolutionary anthropologist , @ @ @ @ @ @ @ @ @ @ Centre ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (818, ' Most importantly , he ''s a dog lover ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (819, ' And , thankfully , he ''s not a blowhard ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (820, 'In journalism , there ''s a warning : When dealing with experts , beware the expertise ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (821, ' The concern is when academics write books , they tend to bash readers over the head with scientific jargon in an effort to ensure everyone understands just how clever they are ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (822, 'Thankfully , Hare , aided by his journalist wife , has crafted a game-changing book that , while faithfully documenting complex research , is clear , jargon-free and relies on a simple narrative style to deliver a truly gripping read ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (823, 'What does Hare mean when he says dogs are geniuses ? Well , he ''s mostly referring to their ability to spontaneously make inferences , to solve problems by reading human gestures ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (824, 'Hare recalls his time working at Emory University under a professor named Mike Tomasello , who was trying to figure out what makes us human ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (825, ' One day , Mike was lamenting that only humans understand " communicative intentions , " which allow @ @ @ @ @ @ @ @ @ @ pointing ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (826, 'At that moment , the author had a flash of insight ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (827, ' " I think my dog can do it , " he blurted ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (828, 'And , through a series of experiments in his parents '' garage with their dog , Oreo , he proved just that ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (829, ' It turns out that dogs have a unique ability to follow human gestures , such as pointing , to locate a food reward hidden under one of a series of plastic cups ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (830, 'In fact , dogs are at the top of the class compared with wolves and chimps and other wild animals ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (831, ' " In short , " Hare writes , " Mike and I concluded that dogs have communicative skills that are amazingly similar to those of infants ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (832, 'The long-standing belief is that domesticated dogs are less intelligent than wild animals such as wolves and foxes , yet the central point of The Genius of Dogs is that the opposite is true -- human contact has actually increased the genius of the species ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (833, 'With a nod to Darwin , Hare says @ @ @ @ @ @ @ @ @ @ A friendly wild dog , one that was willing to tolerate proximity to humans , was favoured with a great reward -- a new food supply known as " garbage ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (834, 'Hare also dispels the myth that scientists have had their senses of humour surgically removed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (835, 'In one chapter , he recounts a hilarious , if uncomfortable , evening spent in a Russian sauna , where the other researchers insisted on calling him " Brain " instead of Brian ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (836, '" I sat naked in a Russian banya , " he writes ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (837, ' " The air in the sauna was so dry and hot , it scorched my windpipe all the way down to my lungs ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (838, ' The other eight Russian men , also naked , were leaning against the cedar walls , their eyes closed in ecstasy , as though slowly roasting yourself alive was the most relaxing thing in the world ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (839, 'There ''s a lot more vodka and jumping through holes in the ice involved , but you can find that out for yourself ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (840, ' We also are n''t going to @ @ @ @ @ @ @ @ @ @ the smartest ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (841, 'You ''re going to have to go out and buy the book ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (842, ' In fact , we suggest you pick up two -- get one for your dog , because , after all , he ''s a genius ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (843, 'Book review') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (844, 'History') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (845, 'Updated on Saturday , February 16 , 2013 at 1:43 PM CST : adds fact box') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (846, 'You can comment on most stories on winnipegfreepress') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (847, ' You can also agree or disagree with other comments ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (848, ' All you need to do is be a Winnipeg Free Press print or e-edition subscriber to join the conversation and give your feedback ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (849, '

A novel experiment that gives rats the ability to " feel " infrared light by hijacking their sense of touch may require scientists to re-evaluate their ideas about how the brain works , says the lead researcher behind the study ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (850, 'Six rats were implanted with electrodes that connect their brains to infrared sensors they wore on the tops of their heads ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (851, ' The electrodes were inserted into each animal ''s somatosensory cortex -- the part of a rat ''s brain that is responsible for sensing touch , particularly through the whiskers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (852, 'Multimedia') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (853, 'Hacking the Brain') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (854, 'When the wired rats were placed in a situation where infrared lights were turned on and off around them , they first responded as though they were feeling an invisible touch to their whiskers ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (855, ' Within a few days , however , the rats '' responses changed and they were able to identify and move toward sources of infrared light as though " seeing " them in the distance ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (856, '" They basically started behaving like they ''re projecting the sensation of touch into the @ @ @ @ @ @ @ @ @ @ of neurobiology and bioengineering at Duke University in Durham , North Carolina , who led the experiment ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (857, 'What is especially intriguing is that Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (858, ' Nicolelis and his colleagues made no special effort to connect the infrared sensors to specific neurons apart from placing then in the general brain region associated with touch ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (859, '" We did n''t have to go fishing for the right cells , " says Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (860, ' Nicolelis ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (861, 'The results suggest that adult brains are for more plastic than expected and , aided by so-called neuro-prosthetic devices , can quickly develop new sensory modalities that operate on top of the conventional five senses ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (862, ' Nicolelis says the work could lead to ways of helping human patients acquire a different kind of sight even when the visual cortex is damaged ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (863, ' Currently , damage to the brain ''s visual processing centre is considered an insurmountable barrier to regaining a sense of sight ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (864, 'In the future , Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (865, ' Nicolelis adds , people who suffer no impairments at all may opt to add to their sensory capabilities with implants that allow them to @ @ @ @ @ @ @ @ @ @ " I tell my students that Superman must have a neuro-prosthesis for X-ray vision , " says Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (866, ' Nicolelis ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (867, 'The study , published in the journal Nature Communications , is one of several illustrating the rapid advancements under way in brain-machine interfaces ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (868, ' The field is the focus of a session on Sunday at the annual meeting of the American Association for the Advancement of Science in Boston ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (869, 'The work has also attracted the attention of bioethicists exploring how technologies that enhance the brain may one day change our concept of what it means to be human ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (870, ' Despite the futuristic nature of the technology , it not too soon to discuss its implications , says Martha Farah , director of the Center for Neuroscience and Society at the University of Pennsylvania in Philadelphia ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (871, '" Part of the point in having discussions at this stage , in anticipation of these technologies being available , is that we can perhaps decide how would we like our society to manage and guide their use , " says Dr') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (872, ' Farah ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (873, 'Restrictions') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (874, 'All rights reserved ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (875, ' @ @ @ @ @ @ @ @ @ @ framing or similar means , is prohibited without the prior written consent of Thomson Reuters ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (876, ' Thomson Reuters is not liable for any errors or delays in Thomson Reuters content , or for any actions taken in reliance on such content ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (877, ' '' Thomson Reuters '' and the Thomson Reuters logo are trademarks of Thomson Reuters and its affiliated companies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (878, ' video') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (879, 'video') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (880, 'If you said ( f ) , you ''re right ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (881, ' In the perfumed salons of Rosedale , Toronto ''s gilded midtown neighbourhood , I have heard people whisper about another that " she really should do something about those lines " as though a shot of Botox is a matter of simple maintenance , like having your leaves blown off your lawn ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (882, ' To not do it is seen as a failure of community manners ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (883, 'I have also observed women who submit to the facial needle out of a sense of obligation to their physical beauty ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (884, ' They may never say this , of course , but the sentiment is there ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (885, ' That their effort to preserve it often goes awry and they end up looking like plastic of themselves ( I ''m looking at you , Nicole Kidman ) is not the point ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (886, ' It ''s often a function of identity : They are their beauty ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (887, ' Not to try to sustain it is akin to not fully using the brain you were born with ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (888, 'And @ @ @ @ @ @ @ @ @ @ look like a grouch when they do n''t feel they are ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (889, ' In her book Lots of Candles , Plenty of Cake , Anna Quindlen , the 60-year-old novelist and journalist who famously chronicled thirtysomething life back in the 1980s , wrote that she started using Botox for her frown lines in her mid-50s because she did n''t want to look cross when she was n''t ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (890, ' " And it ''s addictive , " she told me with a laugh when I interviewed her about the book ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (891, ' This is where the Botox-as-sex metaphor comes in ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (892, ' Once you get a taste of it , it ''s hard not to want a repeat , er , injection ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (893, 'It is the treatment of depression through Botox , though , that is as new as a baby ''s skin ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (894, ' In The Face of Emotion : How Botox Affects Our Moodsand Relationships , released two weeks ago , Eric Finzi , a dermatological surgeon , writes of the link between facial expressions and emotions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (895, ' His theories and anecdotal evidence have recently been corroborated by thorough medical studies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (896, ' ( Incidentally @ @ @ @ @ @ @ @ @ @ d ) above , which he heard from one of his patients ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (897, 'It ''s not simply that a Botox injection to the face can make you feel happier because you look better ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (898, 'That ''s the assumption many make , Finzi acknowledges in an interview from Chevy Chase , Md') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (899, ' , where he lives and works ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (900, ' And he does n''t dispute that looking good makes you feel good -- that ''s his business after all ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (901, 'Rather , Finzi ''s work centres around the new and controversial idea that our facial expressions not only reflect our emotions , but also cause them ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (902, ' It ''s a " facial feedback theory of emotion " that he describes as a continuous looping of signals or pathways between muscles and the brain ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (903, ' Basically , the more you frown , the more the brain experiences negative messaging ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (904, ' So when Botox inhibits the frown muscle , " that electrical circuit is clamped off , " Finzi explains over the phone ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (905, 'In 2003 , he started a clinical trial to test his hypothesis that Botox inhibition of @ @ @ @ @ @ @ @ @ @ scientific theories from the 19th century , including Charles Darwin ''s The Expression of the Emotions in Manand Animals , in which the celebrated scientist wrote : " The free expression by outward signs of an emotion intensifies it ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (906, ' On the other hand , the repression , as far as this is possible , of all outward signs softens our emotions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (907, 'Finally , Finzi realized that he had a way to test ancient hypotheses with a modern tool : Botox ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (908, 'His small studies also piqued the interest of Axel Wollmer , a psychiatrist at the University of Basel in Switzerland ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (909, ' Last year , results of his randomized controlled study on the effects of Botox on depression were published in the Journal of Psychiatric Research , showing significant statistical results ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (910, ' The study investigated whether patients who suffered from clinical depression and had not responded to antidepressant medications could be helped with Botox injections in their frown lines ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (911, 'Participants in the treatment group were given a single dose of Botox ( five injections ) between and just above their eyebrows ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (912, ' An equal-sized @ @ @ @ @ @ @ @ @ @ Botox , symptoms of depression decreased 47 per cent after six weeks and lasted through the 16-week study period ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (913, ' In the placebo group , there was a nine per cent reduction in symptoms ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (914, ' Wollmer concluded that Botox " interrupts feedback from the facial musculature to the brain , which may be involved in the development and maintenance of negative emotion ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (915, 'What has hindered investigations into Botox and depression is the stigma it carries as merely a tool for the vain even though its uses for medical conditions such as cerebral palsy , Parkinson ''s disease and migraines are well known , Finzi says ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (916, '" Do n''t blame the molecule ! " he implores with a laugh ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (917, ' " Do n''t attach whatever feelings you have about cosmetic procedures to its potential usefulness for other things ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (918, ' I would predict that , by the end of 2013 , there will be not only one but three randomized , controlled , double-blind tests that will have been completed ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (919, 'And when all three are published , that will be very powerful stuff ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (920, '@ @ @ @ @ @ @ @ @ @ pharmaceutical companies ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (921, 'Depression , of course , is a serious problem ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (922, ' And anything that can help alleviate it is significant ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (923, ' But I ca n''t help but think that this news would provide the perfect excuse for indulging in Botox from here on in ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (924, ' " It ''s not for my vanity , darling , " you could say at swishy soirees as your friends notice your newly unfurrowed brow ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (925, '

Women and visible minorities are underrepresented in senior leadership positions across Montreal , according to a report published by Ryerson University ''s Diversity Institute and the Desautels Faculty of Management at McGill ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (926, 'The report -- part of DiversityLeads , a five-year , $2') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (927, '5-million project funded by the federal Social Sciences and Humanities Research Council ( SSHRC ) -- aims to " benchmark and assess the progress of diversity in leadership " to develop specific solutions to advance diversity across Canada ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (928, ' It examined six sectors : elected , public , private , education , voluntary , and appointments to Agencies , Boards and Commissions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (929, 'The study found that women accounted for 31') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (930, '2 per cent of senior leadership positions , despite comprising 51') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (931, '7 per cent of the population of surveyed areas in greater Montreal ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (932, 'The figure for visible minorities was even lower , standing at only 5') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (933, '9 per cent , despite visible minorities comprising 22') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (934, '5 per cent of the population ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (935, ' The problem compounds itself for women that are visible minorities , who represent 11') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (936, '5 per cent of the population , but @ @ @ @ @ @ @ @ @ @ The corporate sector was found to be the least diverse , with women at 15') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (937, '1 per cent and minorities at 2') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (938, '6 per cent ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (939, ' By comparison , the government and education sectors both had over 40 per cent women , with 9') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (940, '6 and 6') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (941, '4 per cent visible minorities , respectively ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (942, 'Wendy Cukier , founder and director of the Diversity Institute at Ryerson University and a lead researcher on the project , highlighted the significance of the sector-based approach to this research in an email to The Daily ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (943, 'In a phone interview with The Daily , Suzanne Gagnon , another researcher on the project and a professor of organizational behaviour at Desautels , warned that sector averages should not necessarily be taken at face value , and that there is often a wide range of representation within sectors ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (944, ' She suggested that certain organizations could act as models for others within the same sector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (945, 'She explained that phase two of the research would include a cross-sectoral survey and case studies to discover specific reasons for , and solutions to , the problem ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (946, 'Gagnon emphasized @ @ @ @ @ @ @ @ @ @ the top of an organization has been linked to a company or organization ''s ability to retain top talent , and also as a separate issue -- although they are linked to an extent -- to innovate , to make innovative and creative decisions drawing on multiple perspectives ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (947, 'She also explained that , " it matters for young people and for their aspirations and for social inclusion more generally to have leaders who broadly represent the population ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (948, 'Elizabeth Groeneveld , a faculty lecturer and chair of the Women ''s Studies program at McGill , explained that underrepresentation in leadership in Montreal is likely linked to broader systemic racism and sexism ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (949, '" There can be impediments in terms of access to education and the kind of mentoring that is often given to men or people who are racialized as white that is not always extended in the same way to women and visible minorities , " said Groeneveld ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (950, 'Gagnon , in reference to both the corporate sector and as a general trend , described how organizations are " self-reproducing entities " that @ @ @ @ @ @ @ @ @ @ a systemic obstacle to introducing women and visible minorities ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (951, 'Groeneveld echoed this idea : " The language of being '' the right fit '' for a company can sometimes become code for people who look like us , think like us , and talk like us ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (952, 'Cukier noted that several other projects are in progress as part of DiversityLeads , including studies on the representation of Aboriginal people , persons with disabilities , and members of LGBT communities , as well as analysis on the impact of representations of leadership in media ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (953, ' Gagnon mentioned that similar studies were also conducted in other major Canadian cities , including Vancouver and Toronto ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (954, ' Private prisons '' are run better '' than those in public sector') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (955, 'Private firms are better at running prisons than the public sector and all jails should be subject to open competition , an independent think-tank said today ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (956, 'Better staff-prisoner relationships , boosted by the use of first names and mentoring schemes , help rid private jails of hostilitiesPhoto : PA') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (957, '2:45AM GMT 21 Feb 2013') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (958, 'The Government would be wrong to limit the role of private companies within prisons to small contracts such as maintenance and catering , the right-leaning group Reform said ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (959, 'Some 10 out of 12 privately managed prisons have lower reoffending rates among offenders serving 12 months or more than comparable public sector prisons , Reform found ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (960, 'Meanwhile , the group also called for the end to national pay bargaining for prison officers with pay and conditions to be set locally by governors ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (961, 'The coalition Government denied there had been a '' '' U-turn '' '' on the use of prison competition , while campaigners for prison reform said it was almost @ @ @ @ @ @ @ @ @ @ Tanner , who penned the report The Case for Private Prisons , said : '' '' Twenty years of private prisons have created an effective market which is ready to grow ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (962, ' Evidence shows that a greater role for the private sector will advance the '' rehabilitation revolution '' which ministers want to deliver ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (963, 'Private firms have been managing prisons since 1992 , but in November last year Justice Secretary Chris Grayling signalled a move away from wholesale privatisation as he decided four prisons , including G4S-run HMP Wolds , should be run by the public sector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (964, 'Two contracts to run five prisons -- Acklington and Castington , which have since formed Northumberland prison , and three in South Yorkshire -- will proceed to the next stage of the competition with an announcement expected next spring ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (965, 'Mr Grayling said private firms will be brought in to all public prisons to run maintenance , resettlement and catering to save up to ? 450 million over six years ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (966, 'Policy groups , including Reform , said the decision amounted to the end of competition @ @ @ @ @ @ @ @ @ @ although Mr Grayling insisted it did not rule out further prison-by-prison competitions in the future ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (967, 'Looking at Ministry of Justice data , Reform said this decision was not supported by analysis of prison effectiveness ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (968, 'Some seven out of 10 privately managed prisons have lower reoffending rates among offenders serving fewer than 12 months , compared to comparable public sector prisons ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (969, 'Furthermore , Reform said private prisons outperform their public counterparts in four of the performance measures used by the MoJ ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (970, 'A total of 12 out of 12 private jails performed better than the public sector at '' '' resource management and operational effectiveness '' '' , while seven out of 12 were better at '' '' reducing re-offending '' '' ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (971, 'However , seven out of 12 public prisons performed better than private jails at '' '' public protection '' '' ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (972, 'In the report , Mr Tanner argues : '' '' Private contractors outperform comparable public sector prisons on both cost and quality , delivering better value for money for the taxpayer ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (973, ''' '' In addition , the @ @ @ @ @ @ @ @ @ @ similar public sector prisons for both long and short-term prisoners , a key Government objective ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (974, 'As a result , Reform recommends that all prisons should be subject to competition including the private sector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (975, 'It also calls for local pay decision-making to be introduced in prisons , with governors taking on responsibility for deciding staffing arrangements , pay and conditions and performance-related pay ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (976, 'This would spell the end of national pay bargaining for prison officers , a move that would spark fury among unions ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (977, 'Mr Tanner said : '' '' Market-facing pay and adaptable staffing arrangements have not only reduced cost considerably but also improved staff-prisoner relationships and internal cultures within prisons ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (978, 'Justice Minister Jeremy Wright said : '' '' Reoffending rates across the entire prison estate are too high and we are pressing ahead with major reforms to tackle this unacceptable problem ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (979, ''' '' And let ''s be clear -- there has been no U-turn on the use of prison competition ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (980, ''' '' The cost of running our prisons is too high and @ @ @ @ @ @ @ @ @ @ new approach for reducing costs and improving services aimed at reducing reoffending at a faster rate involving the private sector ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (981, 'Mr Wright added : '' '' This simplistic analysis does not tell the whole story -- a wide range of factors contribute to reoffending including previous criminal behaviour , drug and alcohol dependency and the support offenders receive on release from prison ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (982, ' This is why we are committed to introducing significant reforms that will bring down our stubbornly high reoffending rates ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (983, 'She said : '' '' It is almost impossible to compare the performance and reoffending rates of one establishment with another , partly because prisons hold different categories of offenders and also because prisoners often serve their sentences in a number of different jails ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (984, ' '' '' \n') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (985, '

It ''s thought that the chemical resveratrol , found in red grapes and red wine , is the reason why ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (986, 'Resveratrol , a chemical found in red grapes and red wine , may protect against hearing loss') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (987, 'This is the same compound that has been linked with other positive health benefits such as preventing cancer and heart disease ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (988, 'In a study conducted at the Henry Ford Hospital in Detroit , healthy rats were less likely to suffer noise-induced hearing loss when given resveratrol before being exposed to loud noise for a long period of time ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (989, 'RELATED ARTICLES') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (990, 'Share this article') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (991, 'Share') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (992, 'Study leader Dr Michael Seidman said : '' Our latest study focuses on resveratrol and its effect on the body ''s response to injury - something that is believed to be the cause of many health problems including Alzheimer ''s disease , cancer , ageing and hearing loss ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (993, 'Resveratrol appeared to reduce the damage to hearing from loud noises') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (994, ''' Resveratrol is a very powerful chemical that seems to protect against the body @ @ @ @ @ @ @ @ @ @ cognition brain function and hearing loss ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (995, 'Hearing loss affects half of people over the age of 60 , but many begin to suffer problems in their 40s or 50s ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (996, 'It usually sets in with the death of tiny '' hair '' cells in the inner ear as a result of ageing ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (997, 'The study found that resveratrol reduced noise-induced hearing loss in rats exposed to potentially deafening sounds ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (998, 'Dr Seidman said : '' We ''ve shown that by giving animals resveratrol , we can reduce the amount of hearing and cognitive decline ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (999, 'The study is published in the journal Otolaryngology-Head and Neck Surgery ') +GO +~~ROW COUNT: 1~~ + + +INSERT INTO fts_contains_vu_t VALUES (1000, 'Last month , scientists from the Hebrew University of Jerusalem reported that washing down red meat with a glass of red can actually prevent the build-up of cholesterol in the body ') +GO +~~ROW COUNT: 1~~ + + +-- disable CONTAINS +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO +~~START~~ +text +strict +~~END~~ + diff --git a/test/JDBC/expected/fts-contains-vu-verify.out b/test/JDBC/expected/fts-contains-vu-verify.out new file mode 100644 index 0000000000..5d88b8ad0a --- /dev/null +++ b/test/JDBC/expected/fts-contains-vu-verify.out @@ -0,0 +1,345 @@ +-- psql +-- enable CONTAINS +ALTER SYSTEM SET babelfishpg_tsql.allow_fulltext_parser = on; +SELECT pg_reload_conf(); +GO +~~START~~ +bool +t +~~END~~ + + +-- tsql user=jdbc_user password=12345678 +-- enable CONTAINS +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'ignore', 'false') +GO +~~START~~ +text +ignore +~~END~~ + + +-- Test sys.babelfish_fts_contains_pgconfig +SELECT * FROM fts_contains_pgconfig_v1 +GO +~~START~~ +text +fts_contains_simple +~~END~~ + + + +-- Full syntax of CONTAINS: https://github.com/MicrosoftDocs/sql-docs/blob/live/docs/t-sql/queries/contains-transact-sql.md +-- test basic CONTAINS use: ... CONTAINS(col_name, ) ... +-- ::= { word | "phrase" } +EXEC fts_contains_vu_prepare_p1 'love' +GO +~~START~~ +int#!#text +45#!#Rina : I love that ! +655#!# This is now a convention we are familiar with too , in theatre in particular -- The Phantom of the Opera is also about a disfigured face that needs love +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'other' +GO +~~START~~ +int#!#text +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'arts' +GO +~~START~~ +int#!#text +124#!# Reflecting on a quarter-century of growth in Portland 's performing arts scene +125#!#The highlight of the Portland Center for Performing Arts ' grand-opening in 1987 was a performance by high-wire artists Phillippe Petit and Ann Seward , which reflected the thrilling risk the city had taken with the project +130#!#These days , Portland theater , and the city 's arts scene in general , is n't so stripped down +137#!# But the size , scope and solidity of the arts in Portland is something that 's grown over the past quarter century +138#!#That 1987 and ' 88 marked a pivotal time in Portland arts was clear even then +144#!#" Ten or 20 years from now , few will remember all the effort , dreaming , planning and yes , the bickering , mistakes and accusations that marked the creation of the Portland Center for the Performing Arts , " The Oregonian 's Joan Laatz wrote in August , 1987 , when the multi-use New Theater Building ( now named Antoinette Hatfield Hall ) opened +152#!# The fear was that higher production costs in the new facilities would make things tougher for most local arts companies , and that the venerable OSF @ @ @ @ @ @ @ @ @ @ +169#!#" I think the arts scene was like a young teenager then and has grown up a lot , " says Regional Arts & Culture Council executive director Eloise Damrosch , who moved to Portland in ' 87 +184#!# The arts -- in tandem with food , beer and wine -- have raised us up +192#!# Hampton points to Tom Manley , president of Pacific Northwest College of Art as " probably the best leader of an arts organization the city has +199#!#All together , what 's changed and what 's stayed the same add up to an arts scene that , while still facing major challenges , has grown bigger , wider and better integrated into the world around it +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'performing' +GO +~~START~~ +int#!#text +124#!# Reflecting on a quarter-century of growth in Portland 's performing arts scene +125#!#The highlight of the Portland Center for Performing Arts ' grand-opening in 1987 was a performance by high-wire artists Phillippe Petit and Ann Seward , which reflected the thrilling risk the city had taken with the project +144#!#" Ten or 20 years from now , few will remember all the effort , dreaming , planning and yes , the bickering , mistakes and accusations that marked the creation of the Portland Center for the Performing Arts , " The Oregonian 's Joan Laatz wrote in August , 1987 , when the multi-use New Theater Building ( now named Antoinette Hatfield Hall ) opened +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'performance' +GO +~~START~~ +int#!#text +125#!#The highlight of the Portland Center for Performing Arts ' grand-opening in 1987 was a performance by high-wire artists Phillippe Petit and Ann Seward , which reflected the thrilling risk the city had taken with the project +140#!# The idea for a set of new performance spaces began taking place around 1976 due to dissatisfaction with Civic Auditorium @ @ @ @ @ @ @ @ @ @ satisfying venue ) +168#!# Now , Oregon Ballet Theatre ( the result of a merger of the aforementioned ballet troupes ) survives , White Bird does concert presenting at @ @ @ @ @ @ @ @ @ @ Polaris Dance Theatre each have performance spaces and expanding reputations +185#!#The building of the PCPA has n't solved all of the performance-space issues for local companies ( there 's a big , problematic gap between the 900-seat Newmark and the Schnitzer and Keller , which seat close to 3,000 ) +630#!# Lydon has said in interviews , and in his autobiography , that this stage persona was partly inspired by Laurence Olivier 's performance of Richard III , in his 1955 film based on the Shakespeare play +969#!#Furthermore , Reform said private prisons outperform their public counterparts in four of the performance measures used by the MoJ +975#!#It also calls for local pay decision-making to be introduced in prisons , with governors taking on responsibility for deciding staffing arrangements , pay and conditions and performance-related pay +983#!#She said : ' ' It is almost impossible to compare the performance and reoffending rates of one establishment with another , partly because prisons hold different categories of offenders and also because prisoners often serve their sentences in a number of different jails +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'quick' +GO +~~START~~ +int#!#text +466#!#Also , putting professional cameras on a Quad , it will need to be a fairly large quad , and the batteries will sort of run out pretty quick +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'grow' +GO +~~START~~ +int#!#text +134#!# Sure , the city 's artsy eccentricities can grow ripe for lampooning , as the TV spoof " Portlandia " has proved +151#!#More so than social stature , the goal was for the PCPA to both bring more touring talents to town and give local troupes a comfortable home that would help them grow their audiences , and for PCS to provide a model of quality , stability and professionalism that might lift the community as a whole +961#!#The coalition Government denied there had been a ' ' U-turn ' ' on the use of prison competition , while campaigners for prison reform said it was almost @ @ @ @ @ @ @ @ @ @ Tanner , who penned the report The Case for Private Prisons , said : ' ' Twenty years of private prisons have created an effective market which is ready to grow +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'actually' +GO +~~START~~ +int#!#text +32#!#Anne : Marriage equality , which was in the runoff for word of the year , actually won most likely to succeed +189#!# " They actually made a case that a great city needs great art , " says BodyVox co-founder Jamey Hampton +218#!# As you may remember , we followed a thread for several years over how fast photos are deleted from Facebook 's servers once you delete them from the site ; as of late 2012 , we verified that photos indeed appear to be removed within 30 days of deletion ( our tests showed they were actually removed much faster ) +238#!# But if you actually go through with a real deletion , the information should n't be there past 90 days -- and hopefully it will be gone sooner +457#!#The name drone actually means a dumb worker ( as in drone bee +458#!#People somehow have only associated the word with semi-autonomous killer drones ( which are actually usually manually piloted , which is why they tend to crash all the time +465#!#Your Insurance company is unlikely to offer cover , therefore actually having a viable business using such craft @ @ @ @ @ @ @ @ @ @ ) +473#!# But what I discovered after using it for a full day is it 's actually surprisingly great +663#!# This was around 1592 -- 75 years before Milton 's attractively tortured Satan , in Paradise Lost , became a model for sexy villains @ @ @ @ @ @ @ @ @ @ found evidence that the real Richard III was not only actually deformed but that his life of battle was truly an ugly one +832#!#The long-standing belief is that domesticated dogs are less intelligent than wild animals such as wolves and foxes , yet the central point of The Genius of Dogs is that the opposite is true -- human contact has actually increased the genius of the species +1000#!#Last month , scientists from the Hebrew University of Jerusalem reported that washing down red meat with a glass of red can actually prevent the build-up of cholesterol in the body +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'helped' +GO +~~START~~ +int#!#text +187#!# But those two big moves have , over time , proved @ @ @ @ @ @ @ @ @ @ other developments have helped shape the Portland of today +262#!#Prosecutors say the arms have helped fuel conflicts and support regimes in Afghanistan , Angola , The Democratic Republic of the Congo , Liberia , Rwanda , Sierra Leone and Sudan +682#!#" I want people to understand what these women have been through before they start accusing the doctors who helped them of being murderers , " said Carol +910#!# The study investigated whether patients who suffered from clinical depression and had not responded to antidepressant medications could be helped with Botox injections in their frown lines +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 'version' +GO +~~START~~ +int#!#text +7#!# ( Indeed , in Yurick 's book , the gang 's mascot , Junior , reads a comic book version of @ @ @ @ @ @ @ @ @ @ , each faction was given a name and a costume theme invoking it , typified by the iconic " Baseball Furies " the protagonist Warriors fight in Riverside Park +17#!# It is playable only on the PlayStation 2 and original Xbox ; a version for the PSP was released in 2007 +652#!# The idea , with every new version of the play , is to add to the character 's complexity , to make him more than a mere psycho +804#!# All dog owners , in their heart of hearts , are convinced their drooling pet is the canine version of Einstein , only with better grooming +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"come back"' +GO +~~START~~ +int#!#text +6#!#Walter Hill , the director of The Warriors , strove to give a comic-book depiction of the gang 's flight from the Bronx back to their Coney Island turf +8#!# After making their way through rival gangs ' turf in Manhattan and then back to Coney Island , the Warriors defeat the gang responsible for Cyrus ' death +158#!# What were the largest or most active homegrown companies back in the late ' 80s -- Portland Rep , New Rose , Storefront Portland Civic Theater -- long ago folded +174#!#" Back then , there was this grittier , shoestring quality that imbued almost every company , " Mulligan says +176#!# But when I look back at that earlier renaissance of the ' 80s , the truth was the talent pool of the city needed to step up +290#!# I ca n't wait to get back in the ring with Michael +325#!#Judge Linnane , who adjourned the hearing briefly until the terms of settlement were lodged in the court file , put the summary judgment application back for mention on March 6 next +362#!#FRENKEL : Saher says that she never thought she would become a refugee , and it scares her to think about what 's happening back in her hometown of Daraa +416#!# At Mission Dolores , CyArk worked hard to get behind the very ornately carved reredos , a false wall in back of the altar that was made in Mexico and shipped to the Mission by boat in 1796 +720#!#The Australopithecus boisei skull was one of several important discoveries Leakey made in her career -- all made despite the fact that she had nearly @ @ @ @ @ @ @ @ @ @ She got thrown out of school very early on and never wanted to go back , and became hugely interested in archaeology , " Richard Leakey , her son , told Archaeology magazine +889#!# In her book Lots of Candles , Plenty of Cake , Anna Quindlen , the 60-year-old novelist and journalist who famously chronicled thirtysomething life back in the 1980s , wrote that she started using Botox for her frown lines in her mid-50s because she did n't want to look cross when she was n't +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"much of the"' +GO +~~START~~ +int#!#text +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"due to"' +GO +~~START~~ +int#!#text +140#!# The idea for a set of new performance spaces began taking place around 1976 due to dissatisfaction with Civic Auditorium @ @ @ @ @ @ @ @ @ @ satisfying venue ) +408#!# These sites are at risk , endangered due to everyday exposure to the elements , vandalism , war , urbanization , poorly managed tourism , catastrophic events , and general neglect +511#!#A trial was due to be held next month , but Melissa was told last week that the CPS were dropping the case due to " insufficient evidence " +562#!# Loans characterized by low down payments @ @ @ @ @ @ @ @ @ @ early accumulations of interest due , or involve balloon or variable future payments , have a higher default rate than more traditional loans +705#!# Black guessed that any aborted @ @ @ @ @ @ @ @ @ @ due to the " private choice " of a mother +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"per cent"' +GO +~~START~~ +int#!#text +741#!#38 per cent +745#!#76 per cent +753#!#20 per cent +757#!#48 per cent +763#!#78 per cent 3 +764#!#48 per cent respectively +912#!# An equal-sized @ @ @ @ @ @ @ @ @ @ Botox , symptoms of depression decreased 47 per cent after six weeks and lasted through the 16-week study period +913#!# In the placebo group , there was a nine per cent reduction in symptoms +930#!#2 per cent of senior leadership positions , despite comprising 51 +931#!#7 per cent of the population of surveyed areas in greater Montreal +933#!#9 per cent , despite visible minorities comprising 22 +934#!#5 per cent of the population +936#!#5 per cent of the population , but @ @ @ @ @ @ @ @ @ @ The corporate sector was found to be the least diverse , with women at 15 +937#!#1 per cent and minorities at 2 +938#!#6 per cent +939#!# By comparison , the government and education sectors both had over 40 per cent women , with 9 +941#!#4 per cent visible minorities , respectively +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"so-called"' +GO +~~START~~ +int#!#text +561#!#None of these is inherently inappropriate , but they are risky , in much the same way that so-called subprime mortgage lending is risky +861#!#The results suggest that adult brains are for more plastic than expected and , aided by so-called neuro-prosthetic devices , can quickly develop new sensory modalities that operate on top of the conventional five senses +~~END~~ + + + +EXEC fts_contains_vu_prepare_p1 '"stand up"' +GO +~~START~~ +int#!#text +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"every month"' +GO +~~START~~ +int#!#text +495#!#Every month , M +527#!#Trinity Mirror Merseyside , the Echo 's parent company , is one of the North West 's largest multimedia providers reaching more than 900,000 adults every month +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"as a result"' +GO +~~START~~ +int#!#text +168#!# Now , Oregon Ballet Theatre ( the result of a merger of the aforementioned ballet troupes ) survives , White Bird does concert presenting at @ @ @ @ @ @ @ @ @ @ Polaris Dance Theatre each have performance spaces and expanding reputations +681#!#Carol 's fetus was killed by the procedure , but it was virtually identical to those that result in live births +690#!#Less severe condition are survivable , although they result in physical deformities into adulthood +974#!#As a result , Reform recommends that all prisons should be subject to competition including the private sector +996#!#It usually sets in with the death of tiny ' hair ' cells in the inner ear as a result of ageing +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"in Australia"' +GO +~~START~~ +int#!#text +239#!#

NEW YORK -- An associate of a notorious Russian arms dealer was arrested in Australia and charged with conspiring to buy planes so that weapons could be transported to the world 's bloodiest conflicts , a U +462#!#In Australia , if the aircraft is : Away from residential areas , Below 400 feet above the ground ( yep I know that is fairly low ) Within eyesight of the operator Under 150 kg weight ( but getting clearance from the MAAA for over 50kg is a bit hard ) +468#!#( If the above rules are met , there is no regulation in Australia ( Check out the CASA website , they say it in as few words +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"daily news"' +GO +~~START~~ +int#!#text +479#!#Get daily news by email +501#!#Get daily news by email +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '" daily"' +GO +~~START~~ +int#!#text +89#!# Eighty croissants are made daily for the pastry shop , which is small but well-lit by a storefront of large windows +383#!#Researchers say the results suggest that being lonely can cause people to experience daily life as more stressful , which may cause chronic stress and in turn disrupt the immune system +479#!#Get daily news by email +492#!#Our newspapers include the flagship Manchester Evening News - Britain 's largest circulating regional daily with up to 130,485 copies - as well as 20 local weekly titles across Greater Manchester , Cheshire and Lancashire +501#!#Get daily news by email +529#!#The Liverpool Echo reaches 1 in 3 people in the area with a daily readership of more than 256,000* people +536#!# He is a former editor of The Daily Post ( Wales and England ) and editor-in-chief of the company 's Welsh operations +602#!# If so , the RCAF will be required to monitor Canada 's Arctic on a daily basis +942#!#Wendy Cukier , founder and director of the Diversity Institute at Ryerson University and a lead researcher on the project , highlighted the significance of the sector-based approach to this research in an email to The Daily +943#!#In a phone interview with The Daily , Suzanne Gagnon , another researcher on the project and a professor of organizational behaviour at Desautels , warned that sector averages should not necessarily be taken at face value , and that there is often a wide range of representation within sectors +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"daily "' +GO +~~START~~ +int#!#text +89#!# Eighty croissants are made daily for the pastry shop , which is small but well-lit by a storefront of large windows +383#!#Researchers say the results suggest that being lonely can cause people to experience daily life as more stressful , which may cause chronic stress and in turn disrupt the immune system +479#!#Get daily news by email +492#!#Our newspapers include the flagship Manchester Evening News - Britain 's largest circulating regional daily with up to 130,485 copies - as well as 20 local weekly titles across Greater Manchester , Cheshire and Lancashire +501#!#Get daily news by email +529#!#The Liverpool Echo reaches 1 in 3 people in the area with a daily readership of more than 256,000* people +536#!# He is a former editor of The Daily Post ( Wales and England ) and editor-in-chief of the company 's Welsh operations +602#!# If so , the RCAF will be required to monitor Canada 's Arctic on a daily basis +942#!#Wendy Cukier , founder and director of the Diversity Institute at Ryerson University and a lead researcher on the project , highlighted the significance of the sector-based approach to this research in an email to The Daily +943#!#In a phone interview with The Daily , Suzanne Gagnon , another researcher on the project and a professor of organizational behaviour at Desautels , warned that sector averages should not necessarily be taken at face value , and that there is often a wide range of representation within sectors +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 ' "daily news"' +GO +~~START~~ +int#!#text +479#!#Get daily news by email +501#!#Get daily news by email +~~END~~ + + +EXEC fts_contains_vu_prepare_p1 '"daily news" ' +GO +~~START~~ +int#!#text +479#!#Get daily news by email +501#!#Get daily news by email +~~END~~ + + +-- Prefix Term not supported +EXEC fts_contains_vu_prepare_p1 '"conf*"', 20 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Prefix term is not currently supported in Babelfish)~~ + + +-- Generation Term not supported +EXEC fts_contains_vu_prepare_p1 'FORMSOF(THESAURUS, love)' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Generation term is not currently supported in Babelfish)~~ + + +-- disable CONTAINS +SELECT set_config('babelfishpg_tsql.escape_hatch_fulltext', 'strict', 'false') +GO +~~START~~ +text +strict +~~END~~ + diff --git a/test/JDBC/expected/getdate-vu-cleanup.out b/test/JDBC/expected/getdate-vu-cleanup.out new file mode 100644 index 0000000000..d4ee9cf6b3 --- /dev/null +++ b/test/JDBC/expected/getdate-vu-cleanup.out @@ -0,0 +1,29 @@ +DROP PROCEDURE sysdatetime_dep_proc +go + +DROP PROCEDURE sysdatetimeoffset_dep_proc +go + +DROP PROCEDURE sysutcdatetime_dep_proc +go + +DROP PROCEDURE getdate_dep_proc +go + +DROP PROCEDURE getutcdate_dep_proc +go + +DROP VIEW sysdatetime_dep_view +go + +DROP VIEW sysdatetimeoffset_dep_view +go + +DROP VIEW sysutcdatetime_dep_view +go + +DROP VIEW getdate_dep_view +go + +DROP VIEW getutcdate_dep_view +go diff --git a/test/JDBC/expected/getdate-vu-prepare.out b/test/JDBC/expected/getdate-vu-prepare.out new file mode 100644 index 0000000000..2cbd5e1691 --- /dev/null +++ b/test/JDBC/expected/getdate-vu-prepare.out @@ -0,0 +1,139 @@ +Create procedure sysdatetime_dep_proc +AS + WITH + Pass0 as (select sys.sysdatetime() as C union all select sys.sysdatetime()), --2 rows + Pass1 as (select sys.sysdatetime() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysdatetime() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysdatetime() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysdatetime() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.sysdatetime() +GO + +Create procedure sysdatetimeoffset_dep_proc +AS + WITH + Pass0 as (select sys.sysdatetimeoffset() as C union all select sys.sysdatetimeoffset()), --2 rows + Pass1 as (select sys.sysdatetimeoffset() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysdatetimeoffset() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysdatetimeoffset() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysdatetimeoffset() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.sysdatetimeoffset() +GO + +Create procedure sysutcdatetime_dep_proc +AS + WITH + Pass0 as (select sys.sysutcdatetime() as C union all select sys.sysutcdatetime()), --2 rows + Pass1 as (select sys.sysutcdatetime() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysutcdatetime() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysutcdatetime() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysutcdatetime() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sysutcdatetime() +GO + +Create procedure getdate_dep_proc +AS + WITH + Pass0 as (select sys.getdate() as C union all select sys.getdate()), --2 rows + Pass1 as (select sys.getdate() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.getdate() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.getdate() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.getdate() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.getdate() +GO + +Create procedure getutcdate_dep_proc +AS + WITH + Pass0 as (select sys.getutcdate() as C union all select sys.getutcdate()), --2 rows + Pass1 as (select sys.getutcdate() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.getutcdate() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.getutcdate() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.getutcdate() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.getutcdate() +GO + +Create view sysdatetime_dep_view +AS + WITH + Pass0 as (select sys.sysdatetime() as C union all select sys.sysdatetime()), --2 rows + Pass1 as (select sys.sysdatetime() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysdatetime() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysdatetime() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysdatetime() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.sysdatetime() +GO + +Create view sysdatetimeoffset_dep_view +AS + WITH + Pass0 as (select sys.sysdatetimeoffset() as C union all select sys.sysdatetimeoffset()), --2 rows + Pass1 as (select sys.sysdatetimeoffset() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysdatetimeoffset() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysdatetimeoffset() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysdatetimeoffset() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.sysdatetimeoffset() +GO + +Create view sysutcdatetime_dep_view +AS + WITH + Pass0 as (select sys.sysutcdatetime() as C union all select sys.sysutcdatetime()), --2 rows + Pass1 as (select sys.sysutcdatetime() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysutcdatetime() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysutcdatetime() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysutcdatetime() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sysutcdatetime() +GO + +Create view getdate_dep_view +AS + WITH + Pass0 as (select sys.getdate() as C union all select sys.getdate()), --2 rows + Pass1 as (select sys.getdate() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.getdate() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.getdate() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.getdate() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.getdate() +GO + +Create view getutcdate_dep_view +AS + WITH + Pass0 as (select sys.getutcdate() as C union all select sys.getutcdate()), --2 rows + Pass1 as (select sys.getutcdate() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.getutcdate() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.getutcdate() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.getutcdate() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) + SELECT count(min_getdate) + FROM Tally + WHERE min_getdate = sys.getutcdate() +GO diff --git a/test/JDBC/expected/getdate-vu-verify.out b/test/JDBC/expected/getdate-vu-verify.out new file mode 100644 index 0000000000..740b70ebb7 --- /dev/null +++ b/test/JDBC/expected/getdate-vu-verify.out @@ -0,0 +1,79 @@ +exec sysdatetime_dep_proc +go +~~START~~ +int +65536 +~~END~~ + + +exec sysdatetimeoffset_dep_proc +go +~~START~~ +int +65536 +~~END~~ + + +exec sysutcdatetime_dep_proc +go +~~START~~ +int +65536 +~~END~~ + + +exec getdate_dep_proc +go +~~START~~ +int +65536 +~~END~~ + + +exec getutcdate_dep_proc +go +~~START~~ +int +65536 +~~END~~ + + +Select * from sysdatetime_dep_view +go +~~START~~ +int +65536 +~~END~~ + + +select * from sysdatetimeoffset_dep_view +go +~~START~~ +int +65536 +~~END~~ + + +select * from sysutcdatetime_dep_view +go +~~START~~ +int +65536 +~~END~~ + + +select * from getdate_dep_view +go +~~START~~ +int +65536 +~~END~~ + + +select * from getutcdate_dep_view +go +~~START~~ +int +65536 +~~END~~ + diff --git a/test/JDBC/expected/getdatetest.out b/test/JDBC/expected/getdatetest.out new file mode 100644 index 0000000000..d9ef1499ab --- /dev/null +++ b/test/JDBC/expected/getdatetest.out @@ -0,0 +1,487 @@ + + +-- NOTE: Each test is expected to take a lot of time +-- We do not need Upgrade tests for these function +-- We can only test the stability of this function in the framework since the results are dynamic +WITH + Pass0 as (select sys.sysdatetime() as C union all select sys.sysdatetime()), --2 rows + Pass1 as (select sys.sysdatetime() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysdatetime() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysdatetime() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysdatetime() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) +SELECT count(min_getdate) +FROM Tally +WHERE min_getdate = sys.sysdatetime() +go +~~START~~ +int +65536 +~~END~~ + + +WITH + Pass0 as (select sys.sysdatetimeoffset() as C union all select sys.sysdatetimeoffset()), --2 rows + Pass1 as (select sys.sysdatetimeoffset() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysdatetimeoffset() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysdatetimeoffset() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysdatetimeoffset() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) +SELECT count(min_getdate) +FROM Tally +WHERE min_getdate = sys.sysdatetimeoffset() +go +~~START~~ +int +65536 +~~END~~ + + +WITH + Pass0 as (select sys.sysutcdatetime() as C union all select sys.sysutcdatetime()), --2 rows + Pass1 as (select sys.sysutcdatetime() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.sysutcdatetime() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.sysutcdatetime() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.sysutcdatetime() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) +SELECT count(min_getdate) +FROM Tally +WHERE min_getdate = sysutcdatetime() +go +~~START~~ +int +65536 +~~END~~ + + +WITH + Pass0 as (select sys.getdate() as C union all select sys.getdate()), --2 rows + Pass1 as (select sys.getdate() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.getdate() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.getdate() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.getdate() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) +SELECT count(min_getdate) +FROM Tally +WHERE min_getdate = sys.getdate() +go +~~START~~ +int +65536 +~~END~~ + + +WITH + Pass0 as (select sys.getutcdate() as C union all select sys.getutcdate()), --2 rows + Pass1 as (select sys.getutcdate() as C from Pass0 as A, Pass0 as B),--4 rows + Pass2 as (select sys.getutcdate() as C from Pass1 as A, Pass1 as B),--16 rows + Pass3 as (select sys.getutcdate() as C from Pass2 as A, Pass2 as B),--256 rows + Pass4 as (select sys.getutcdate() as C from Pass3 as A, Pass3 as B),--65536 rows + Tally as (select row_number() over(order by C) as Number, min(C) over () as min_getdate from Pass4) +SELECT count(min_getdate) +FROM Tally +WHERE min_getdate = sys.getutcdate() +go +~~START~~ +int +65536 +~~END~~ + + + +-- Testing for consistency withing a batch and within a transaction as well +-- getdate +declare @a datetime +declare @b datetime +set @a = getdate() +exec pg_sleep 1 +set @b = getdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +Create procedure proc_1 as declare @a datetime;declare @b datetime;set @a = getdate();exec pg_sleep 1;set @b = getdate(); if @a = @b SELECT 'FAILURE' ELSE SELECT 'PASS' +go + +declare @a datetime +declare @b datetime +set @a = getdate() +exec proc_1; +set @b = getdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Begin transaction +go + +declare @a datetime +declare @b datetime +set @a = getdate() +exec pg_sleep 1 +set @b = getdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +declare @a datetime +declare @b datetime +set @a = getdate() +exec proc_1; +set @b = getdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Rollback +go + +Drop procedure proc_1; +go + + +-- getutcdate +declare @a datetime +declare @b datetime +set @a = getutcdate() +exec pg_sleep 1 +set @b = getutcdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +Create procedure proc_1 as declare @a datetime;declare @b datetime;set @a = getutcdate();exec pg_sleep 1;set @b = getutcdate(); if @a = @b SELECT 'FAILURE' ELSE SELECT 'PASS' +go + +declare @a datetime +declare @b datetime +set @a = getutcdate() +exec proc_1; +set @b = getutcdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Begin transaction +go + +declare @a datetime +declare @b datetime +set @a = getutcdate() +exec pg_sleep 1 +set @b = getutcdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +declare @a datetime +declare @b datetime +set @a = getutcdate() +exec proc_1; +set @b = getutcdate() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Rollback +go + +Drop procedure proc_1; +go + +-- sysutcdatetime +declare @a datetime +declare @b datetime +set @a = sysutcdatetime() +exec pg_sleep 1 +set @b = sysutcdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +Create procedure proc_1 as declare @a datetime;declare @b datetime;set @a = sysutcdatetime();exec pg_sleep 1;set @b = sysutcdatetime(); if @a = @b SELECT 'FAILURE' ELSE SELECT 'PASS' +go + +declare @a datetime +declare @b datetime +set @a = sysutcdatetime() +exec proc_1; +set @b = sysutcdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Begin transaction +go + +declare @a datetime +declare @b datetime +set @a = sysutcdatetime() +exec pg_sleep 1 +set @b = sysutcdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +declare @a datetime +declare @b datetime +set @a = sysutcdatetime() +exec proc_1; +set @b = sysutcdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Rollback +go + +Drop procedure proc_1; +go + +-- sysdatetime +declare @a datetime +declare @b datetime +set @a = sysdatetime() +exec pg_sleep 1 +set @b = sysdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +Create procedure proc_1 as declare @a datetime;declare @b datetime;set @a = sysdatetime();exec pg_sleep 1;set @b = sysdatetime(); if @a = @b SELECT 'FAILURE' ELSE SELECT 'PASS' +go + +declare @a datetime +declare @b datetime +set @a = sysdatetime() +exec proc_1; +set @b = sysdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Begin transaction +go + +declare @a datetime +declare @b datetime +set @a = sysdatetime() +exec pg_sleep 1 +set @b = sysdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +declare @a datetime +declare @b datetime +set @a = sysdatetime() +exec proc_1; +set @b = sysdatetime() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Rollback +go + +Drop procedure proc_1; +go + +-- sysdatetimeoffset +declare @a datetime +declare @b datetime +set @a = sysdatetimeoffset() +exec pg_sleep 1 +set @b = sysdatetimeoffset() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +Create procedure proc_1 as declare @a datetime;declare @b datetime;set @a = sysdatetimeoffset();exec pg_sleep 1;set @b = sysdatetimeoffset(); if @a = @b SELECT 'FAILURE' ELSE SELECT 'PASS' +go + +declare @a datetime +declare @b datetime +set @a = sysdatetimeoffset() +exec proc_1; +set @b = sysdatetimeoffset() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Begin transaction +go + +declare @a datetime +declare @b datetime +set @a = sysdatetimeoffset() +exec pg_sleep 1 +set @b = sysdatetimeoffset() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + + +declare @a datetime +declare @b datetime +set @a = sysdatetimeoffset() +exec proc_1; +set @b = sysdatetimeoffset() +if @a = @b SELECT 'FAILURE' + ELSE SELECT 'PASS' +go +~~START~~ +varchar +PASS +~~END~~ + +~~START~~ +varchar +PASS +~~END~~ + + +Rollback +go + +Drop procedure proc_1; +go diff --git a/test/JDBC/expected/host_id-vu-cleanup.out b/test/JDBC/expected/host_id-vu-cleanup.out new file mode 100644 index 0000000000..28569bda9f --- /dev/null +++ b/test/JDBC/expected/host_id-vu-cleanup.out @@ -0,0 +1,5 @@ +DROP VIEW host_id_4272_v1 +GO + +DROP PROCEDURE host_id_4272_p1 +GO diff --git a/test/JDBC/expected/host_id-vu-prepare.out b/test/JDBC/expected/host_id-vu-prepare.out new file mode 100644 index 0000000000..3bcddef65f --- /dev/null +++ b/test/JDBC/expected/host_id-vu-prepare.out @@ -0,0 +1,5 @@ +CREATE VIEW host_id_4272_v1 AS (SELECT CASE WHEN CAST(HOST_ID() AS INT) >= 0 THEN 'HOST_ID() returns number' ELSE 'HOST_ID() unexpected value' END) +GO + +CREATE PROCEDURE host_id_4272_p1 AS (SELECT CASE WHEN CAST(HOST_ID() AS INT) >= 0 THEN 'HOST_ID() returns number' ELSE 'HOST_ID() unexpected value' END); +GO diff --git a/test/JDBC/expected/host_id-vu-verify.out b/test/JDBC/expected/host_id-vu-verify.out new file mode 100644 index 0000000000..b363f1d06a --- /dev/null +++ b/test/JDBC/expected/host_id-vu-verify.out @@ -0,0 +1,33 @@ +SELECT * FROM host_id_4272_v1 +go +~~START~~ +text +HOST_ID() returns number +~~END~~ + + +EXEC host_id_4272_p1 +go +~~START~~ +text +HOST_ID() returns number +~~END~~ + + +SELECT ISNUMERIC(HOST_ID()) +go +~~START~~ +int +1 +~~END~~ + + +SELECT 1 +WHERE (SELECT DISTINCT ISNULL(hostprocess,0) FROM sys.sysprocesses WHERE spid = @@SPID) = CAST(HOST_ID() AS INT) +AND (SELECT DISTINCT ISNULL(host_process_id,0) FROM sys.dm_exec_sessions WHERE session_id = @@SPID) = CAST(HOST_ID() AS INT) +go +~~START~~ +int +1 +~~END~~ + diff --git a/test/JDBC/expected/key_column_usage-vu-cleanup.out b/test/JDBC/expected/key_column_usage-vu-cleanup.out new file mode 100644 index 0000000000..12b2089d55 --- /dev/null +++ b/test/JDBC/expected/key_column_usage-vu-cleanup.out @@ -0,0 +1,33 @@ +USE key_column_usage_vu_prepare_db; +GO + + +DROP VIEW key_column_usage_vu_prepare_v1; +GO + +DROP PROCEDURE key_column_usage_vu_prepare_p1; +GO + +DROP TABLE key_column_usage_vu_prepare_tbl6 +GO + +DROP TABLE key_column_usage_vu_prepare_tbl5 +GO + +DROP TABLE key_column_usage_vu_prepare_sc1.key_column_usage_vu_prepare_tbl4 +GO + +DROP TABLE key_column_usage_vu_prepare_tbl3 +GO + +DROP TABLE key_column_usage_vu_prepare_tbl2 +GO + +DROP TABLE key_column_usage_vu_prepare_tbl1 +GO + +USE master +GO + +DROP DATABASE key_column_usage_vu_prepare_db +GO diff --git a/test/JDBC/expected/key_column_usage-vu-prepare.out b/test/JDBC/expected/key_column_usage-vu-prepare.out new file mode 100644 index 0000000000..18affcf96a --- /dev/null +++ b/test/JDBC/expected/key_column_usage-vu-prepare.out @@ -0,0 +1,32 @@ +CREATE DATABASE key_column_usage_vu_prepare_db; +GO + +USE key_column_usage_vu_prepare_db; +GO + +CREATE TABLE key_column_usage_vu_prepare_tbl1(arg1 int, arg2 int, primary key(arg1)); +GO + +CREATE TABLE key_column_usage_vu_prepare_tbl2(arg3 int, arg4 int, primary key(arg3), foreign key(arg4) references key_column_usage_vu_prepare_tbl1(arg1)); +GO + +CREATE SCHEMA key_column_usage_vu_prepare_sc1; +GO + +CREATE TABLE key_column_usage_vu_prepare_tbl3 (arg5 int, arg6 int, primary key (arg5,arg6)); +GO + +CREATE TABLE key_column_usage_vu_prepare_sc1.key_column_usage_vu_prepare_tbl4 (arg7 int, arg8 int, primary key (arg7) , foreign key (arg7) references key_column_usage_vu_prepare_tbl2(arg3)); +GO + +CREATE TABLE key_column_usage_vu_prepare_tbl5 (arg9 int, arg10 int, arg11 int, foreign key(arg10,arg11) references key_column_usage_vu_prepare_tbl3(arg5,arg6)); +GO + +CREATE TABLE key_column_usage_vu_prepare_tbl6(arg12 int primary key, arg13 int not null unique, arg14 int check(arg14>0), arg15 int, foreign key(arg15) references key_column_usage_vu_prepare_sc1.key_column_usage_vu_prepare_tbl4(arg7)); +GO + +CREATE VIEW key_column_usage_vu_prepare_v1 AS (SELECT * FROM information_schema.key_column_usage WHERE TABLE_NAME LIKE 'key_column_usage_vu_prepare%' ORDER BY constraint_name, column_name); +GO + +CREATE PROCEDURE key_column_usage_vu_prepare_p1 AS (SELECT * FROM information_schema.key_column_usage WHERE TABLE_NAME LIKE 'key_column_usage_vu_prepare%' ORDER BY constraint_name, column_name); +GO diff --git a/test/JDBC/expected/key_column_usage-vu-verify.out b/test/JDBC/expected/key_column_usage-vu-verify.out new file mode 100644 index 0000000000..d840b7c9fe --- /dev/null +++ b/test/JDBC/expected/key_column_usage-vu-verify.out @@ -0,0 +1,70 @@ +USE key_column_usage_vu_prepare_db; +GO + +SELECT * FROM information_schema.key_column_usage WHERE TABLE_NAME LIKE 'key_column_usage_vu_prepare%' ORDER BY constraint_name, column_name; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl1_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl1#!#arg1#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2_arg4_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2#!#arg4#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2#!#arg3#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3#!#arg5#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3#!#arg6#!#2 +key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4_arg7_fkey#!#key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4#!#arg7#!#1 +key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4_pkey#!#key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4#!#arg7#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5_arg10_arg11_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5#!#arg10#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5_arg10_arg11_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5#!#arg11#!#2 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_arg13_key#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg13#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_arg15_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg15#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg12#!#1 +~~END~~ + + +SELECT * FROM key_column_usage_vu_prepare_v1; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl1_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl1#!#arg1#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2_arg4_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2#!#arg4#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2#!#arg3#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3#!#arg5#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3#!#arg6#!#2 +key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4_arg7_fkey#!#key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4#!#arg7#!#1 +key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4_pkey#!#key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4#!#arg7#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5_arg10_arg11_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5#!#arg10#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5_arg10_arg11_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5#!#arg11#!#2 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_arg13_key#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg13#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_arg15_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg15#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg12#!#1 +~~END~~ + + +EXECUTE key_column_usage_vu_prepare_p1; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl1_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl1#!#arg1#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2_arg4_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2#!#arg4#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl2#!#arg3#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3#!#arg5#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl3#!#arg6#!#2 +key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4_arg7_fkey#!#key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4#!#arg7#!#1 +key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4_pkey#!#key_column_usage_vu_prepare_db#!#key_column_usage_vu_prepare_sc1#!#key_column_usage_vu_prepare_tbl4#!#arg7#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5_arg10_arg11_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5#!#arg10#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5_arg10_arg11_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl5#!#arg11#!#2 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_arg13_key#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg13#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_arg15_fkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg15#!#1 +key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6_pkey#!#key_column_usage_vu_prepare_db#!#dbo#!#key_column_usage_vu_prepare_tbl6#!#arg12#!#1 +~~END~~ + + +USE master; +GO + +SELECT * FROM information_schema.key_column_usage WHERE TABLE_NAME LIKE 'key_column_usage_vu_prepare%' ORDER BY constraint_name, column_name; +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#int +~~END~~ + + diff --git a/test/JDBC/expected/kill-vu-cleanup.out b/test/JDBC/expected/kill-vu-cleanup.out new file mode 100644 index 0000000000..3c34eb7d8a --- /dev/null +++ b/test/JDBC/expected/kill-vu-cleanup.out @@ -0,0 +1,19 @@ +-- tsql +DROP LOGIN victim_user_tds +go + +DROP TABLE tab_kill_spid +go + +DROP PROCEDURE kill_proc_1 +go + +DROP PROCEDURE kill_proc_2 +go + +DROP PROCEDURE kill_proc_3 +go + +DROP TABLE tab_kill_test +go + diff --git a/contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.h b/test/JDBC/expected/kill-vu-prepare.out similarity index 100% rename from contrib/babelfishpg_tsql/src/tsqlUnsupportedFeatureHandler.h rename to test/JDBC/expected/kill-vu-prepare.out diff --git a/test/JDBC/expected/kill-vu-verify.out b/test/JDBC/expected/kill-vu-verify.out new file mode 100644 index 0000000000..71b11a7da9 --- /dev/null +++ b/test/JDBC/expected/kill-vu-verify.out @@ -0,0 +1,440 @@ +-- tsql +create table tab_kill_spid(spid int) +go +create login victim_user_tds with password = '12345678'; +go + +-- tsql user=victim_user_tds password=12345678 +select 1 +go +~~START~~ +int +1 +~~END~~ + +-- not allowed: no sysadmin role +KILL 1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: User does not have permission to use the KILL statement)~~ + + +-- tsql user=jdbc_user password=12345678 +/* find a TDS session that is not the current one */ +declare @victim_user_tds int +declare @sql varchar(20) +select top 1 @victim_user_tds = session_id from sys.dm_exec_sessions where login_name = 'victim_user_tds' and session_id <> @@spid +if @victim_user_tds is null +begin +print 'ERROR: no victim spid found' +end +insert tab_kill_spid values(@victim_user_tds) +set @sql = 'kill ' + convert(varchar, @victim_user_tds) +execute(@sql) +go +~~ROW COUNT: 1~~ + + +-- allow the kill to complete; this might take a while under heavy workload +exec pg_sleep 10 +go + +-- verify session does not exist anymore +declare @victim_user_tds int +select @victim_user_tds = spid from tab_kill_spid +select count(distinct session_id) from sys.dm_exec_sessions where session_id = @victim_user_tds +go +~~START~~ +int +0 +~~END~~ + + + +/* Cannot currently be tested: trying to kill a PG session + * Reason is that the error message contains the spid number, which is not predicatable + * and will therefore always lead to a test failure + */ +go + +-- KILL in a procedure: allowed +CREATE PROC kill_proc_1 +as +KILL 1 +go +EXECUTE kill_proc_1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Process ID 1 is not an active process ID)~~ + + +-- KILL not allowed in a SQL function: not allowed +CREATE FUNCTION kill_func() RETURNS INT +AS +BEGIN +KILL 1 +END +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid use of a side-effecting operator 'KILL' within a function.)~~ + + +-- try to kill current TDS session +declare @sql varchar(100) +set @sql = 'kill ' + convert(varchar, @@spid) +execute(@sql) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot use KILL to kill your own process.)~~ + + +-- kill non-existing spid +KILL 1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Process ID 1 is not an active process ID)~~ + + +KILL -123 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '-' at line 1 and character position 5)~~ + + +KILL 999999999999999999999999999999999999999999999 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Session ID -1 is not valid)~~ + + +KILL 123 WITH STATUSONLY +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with STATUSONLY' is not currently supported in Babelfish)~~ + + +KILL UOW WITH STATUSONLY +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with STATUSONLY' is not currently supported in Babelfish)~~ + + +KILL 'A0499C66-F938-45CA-BF7E-E2B6194B48CF' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with a session ID string' is not currently supported in Babelfish)~~ + + +KILL 'A0499C66-F938-45CA-BF7E-E2B6194B48CF' with statusonly +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with STATUSONLY' is not currently supported in Babelfish)~~ + + +KILL STATS JOB 123 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with STATS JOB' is not currently supported in Babelfish)~~ + + +KILL QUERY NOTIFICATION SUBSCRIPTION ALL +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with QUERY NOTIFICATION' is not currently supported in Babelfish)~~ + + +KILL QUERY NOTIFICATION SUBSCRIPTION 123 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: 'KILL with QUERY NOTIFICATION' is not currently supported in Babelfish)~~ + + + +-- error semantics tests: +-- basic: cannot use KILL inside a transaction +BEGIN TRAN +go +KILL 1 +go +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +ROLLBACK +go + +CREATE TABLE tab_kill_test(a INT) +go + +-- cannot use KILL in a transaction, XACT_ABORT=OFF +SET XACT_ABORT OFF +go +BEGIN TRANSACTION +INSERT tab_kill_test values(1) +go +~~ROW COUNT: 1~~ + +PRINT 'before kill' +INSERT tab_kill_test values(2) +KILL 1 +PRINT 'after kill' +INSERT tab_kill_test values(3) +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: before kill Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: before kill Server SQLState: S0001)~~~~WARNING (Message: after kill Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +SELECT @@TRANCOUNT +go +~~START~~ +int +1 +~~END~~ + +SELECT * FROM tab_kill_test +go +~~START~~ +int +1 +2 +3 +~~END~~ + +ROLLBACK +go + +-- cannot use KILL in a transaction, XACT_ABORT=ON +SET XACT_ABORT ON +go +BEGIN TRANSACTION +INSERT tab_kill_test values(1) +go +~~ROW COUNT: 1~~ + +PRINT 'before kill' +INSERT tab_kill_test values(2) +KILL 1 +PRINT 'after kill' +INSERT tab_kill_test values(3) +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: before kill Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +SELECT @@TRANCOUNT +go +~~START~~ +int +0 +~~END~~ + +SELECT * FROM tab_kill_test +go +~~START~~ +int +~~END~~ + + +-- batch is not aborted when KILL in transaction, XACT_ABORT=OFF +SET XACT_ABORT OFF +go +BEGIN TRANSACTION +INSERT tab_kill_test values(1) +go +~~ROW COUNT: 1~~ + +PRINT 'before kill' +INSERT tab_kill_test values(2) +KILL 1 +PRINT 'after kill' +INSERT tab_kill_test values(3) +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: before kill Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: before kill Server SQLState: S0001)~~~~WARNING (Message: after kill Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +SELECT @@TRANCOUNT +go +~~START~~ +int +1 +~~END~~ + +SELECT * FROM tab_kill_test +go +~~START~~ +int +1 +2 +3 +~~END~~ + +ROLLBACK +go + +-- respects XACT_ABORT=ON +SET XACT_ABORT ON +go +BEGIN TRANSACTION +INSERT tab_kill_test values(1) +go +~~ROW COUNT: 1~~ + +PRINT 'before kill' +INSERT tab_kill_test values(2) +KILL 1 +PRINT 'after kill' +INSERT tab_kill_test values(3) +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: before kill Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +SELECT @@TRANCOUNT +go +~~START~~ +int +0 +~~END~~ + +SELECT * FROM tab_kill_test +go +~~START~~ +int +~~END~~ + + +-- KILL in procedure, XACT_ABORT=OFF +CREATE PROCEDURE kill_proc_2 +AS +BEGIN +PRINT 'before kill' +INSERT tab_kill_test values(2) +KILL 1 +PRINT 'after kill' +INSERT tab_kill_test values(3) +END +go +SET XACT_ABORT OFF +go +BEGIN TRANSACTION +INSERT tab_kill_test values(1) +EXECUTE kill_proc_2 +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +~~ROW COUNT: 1~~ + +SELECT @@TRANCOUNT +go +~~START~~ +int +1 +~~END~~ + +SELECT * FROM tab_kill_test +go +~~START~~ +int +1 +2 +3 +~~END~~ + +ROLLBACK +go + +-- KILL in procedure, XACT_ABORT=ON +CREATE PROCEDURE kill_proc_3 +AS +BEGIN +PRINT 'before kill' +INSERT tab_kill_test values(2) +KILL 1 +PRINT 'after kill' +INSERT tab_kill_test values(3) +END +go +SET XACT_ABORT ON +go +BEGIN TRANSACTION +INSERT tab_kill_test values(1) +EXECUTE kill_proc_3 +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 6615)~~ + +~~ERROR (Message: KILL command cannot be used inside user transactions.)~~ + +SELECT @@TRANCOUNT +go +~~START~~ +int +0 +~~END~~ + +SELECT * FROM tab_kill_test +go +~~START~~ +int +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__13_4__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_4__babel_datetime-vu-verify.out index beb8038af8..9e181de4a0 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_4__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_4__babel_datetime-vu-verify.out @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) 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~~ diff --git a/test/JDBC/expected/latest__verification_cleanup__13_5__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_5__babel_datetime-vu-verify.out index beb8038af8..9e181de4a0 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_5__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_5__babel_datetime-vu-verify.out @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/latest__verification_cleanup__13_6__TestDatetimeoffset-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_6__TestDatetimeoffset-vu-verify.out index 0941ca14c3..ff7b640414 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_6__TestDatetimeoffset-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_6__TestDatetimeoffset-vu-verify.out @@ -293,14 +293,14 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime); go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99' AS datetime2) AS datetimeoffset); @@ -314,7 +314,7 @@ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS datetime2 go ~~START~~ datetime2 -1900-05-06 21:59:29.9980000 +1900-05-06 13:59:29.9980000 ~~END~~ @@ -381,7 +381,7 @@ select CAST(CAST('1900-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99 +0' AS datetimeoffset) AS time); @@ -416,7 +416,7 @@ select CAST(CAST('2050-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ @@ -425,21 +425,21 @@ select CAST(CAST('2000-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS smalldate go ~~START~~ smalldatetime -2000-06-07 09:29:00.0 +2000-06-06 23:59:00.0 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -2079-06-06 15:59:00.0 +2079-06-06 23:59:00.0 ~~END~~ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -1900-05-06 21:59:00.0 +1900-05-06 13:59:00.0 ~~END~~ select CAST(CAST('2020-03-15 23:59:29.99' AS smalldatetime) AS datetimeoffset); diff --git a/test/JDBC/expected/latest__verification_cleanup__13_6__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_6__babel_datetime-vu-verify.out index beb8038af8..4107ba9510 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_6__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_6__babel_datetime-vu-verify.out @@ -194,21 +194,21 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:12.347 +2079-06-06 23:59:12.347 ~~END~~ -- out of range @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/latest__verification_cleanup__13_7__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_7__babel_datetime-vu-verify.out index beb8038af8..9e181de4a0 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_7__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_7__babel_datetime-vu-verify.out @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/latest__verification_cleanup__13_8__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_8__babel_datetime-vu-verify.out index beb8038af8..9e181de4a0 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_8__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_8__babel_datetime-vu-verify.out @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/latest__verification_cleanup__13_9__TestDatetimeoffset-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_9__TestDatetimeoffset-vu-verify.out index 0941ca14c3..ff7b640414 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_9__TestDatetimeoffset-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_9__TestDatetimeoffset-vu-verify.out @@ -293,14 +293,14 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime); go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99' AS datetime2) AS datetimeoffset); @@ -314,7 +314,7 @@ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS datetime2 go ~~START~~ datetime2 -1900-05-06 21:59:29.9980000 +1900-05-06 13:59:29.9980000 ~~END~~ @@ -381,7 +381,7 @@ select CAST(CAST('1900-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99 +0' AS datetimeoffset) AS time); @@ -416,7 +416,7 @@ select CAST(CAST('2050-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ @@ -425,21 +425,21 @@ select CAST(CAST('2000-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS smalldate go ~~START~~ smalldatetime -2000-06-07 09:29:00.0 +2000-06-06 23:59:00.0 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -2079-06-06 15:59:00.0 +2079-06-06 23:59:00.0 ~~END~~ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -1900-05-06 21:59:00.0 +1900-05-06 13:59:00.0 ~~END~~ select CAST(CAST('2020-03-15 23:59:29.99' AS smalldatetime) AS datetimeoffset); diff --git a/test/JDBC/expected/latest__verification_cleanup__13_9__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__13_9__babel_datetime-vu-verify.out index beb8038af8..4107ba9510 100644 --- a/test/JDBC/expected/latest__verification_cleanup__13_9__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__13_9__babel_datetime-vu-verify.out @@ -194,21 +194,21 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:12.347 +2079-06-06 23:59:12.347 ~~END~~ -- out of range @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/latest__verification_cleanup__14_10__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_10__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_10__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_10__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_10__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_10__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_10__Test-sp_babelfish_volatility-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_10__Test-sp_babelfish_volatility-vu-cleanup.out new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_10__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_10__Test-sp_babelfish_volatility-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_10__Test-sp_babelfish_volatility-vu-verify.out new file mode 100644 index 0000000000..566b7301e4 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_10__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_3__ISC-Columns-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-cleanup.out index 12eb4ec818..6b112cb429 100644 --- a/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-cleanup.out +++ b/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-cleanup.out @@ -4,6 +4,9 @@ GO DROP VIEW isc_columns_vu_prepare_v1 GO +DROP VIEW isc_columns_bytea_v2 +GO + DROP FUNCTION isc_columns_vu_prepare_f2 DROP FUNCTION isc_columns_vu_prepare_f1 GO @@ -19,4 +22,5 @@ GO DROP TABLE isc_columns_vu_prepare_var DROP TABLE isc_columns_vu_prepare_dates DROP TABLE isc_columns_vu_prepare_nums +DROP TABLE isc_columns_vu_prepare_bytea GO diff --git a/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-verify.out index e64bee2b3d..04446793cb 100644 --- a/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__14_3__ISC-Columns-vu-verify.out @@ -23,15 +23,17 @@ SELECT * FROM information_schema.columns WHERE TABLE_NAME LIKE '%ISC_COLUMNS_VU_ 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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -76,15 +78,17 @@ master#!#dbo#!#isc_columns_vu_prepare_var#!#j#!#10#!##!#YES#!#xml#!#-1#!#- ~~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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -141,20 +145,22 @@ EXEC isc_columns_vu_prepare_p1 GO ~~START~~ int -49 +51 ~~END~~ ~~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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -203,7 +209,7 @@ SELECT * FROM isc_columns_vu_prepare_f2() GO ~~START~~ int -49 +51 ~~END~~ ~~START~~ @@ -228,3 +234,11 @@ master#!#dbo#!#isc_columns_udt#!#b#!#2#!##!#YES#!#varchar#!#10#!#10#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__14_3__TestDatetimeoffset-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_3__TestDatetimeoffset-vu-verify.out index 0941ca14c3..ff7b640414 100644 --- a/test/JDBC/expected/latest__verification_cleanup__14_3__TestDatetimeoffset-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__14_3__TestDatetimeoffset-vu-verify.out @@ -293,14 +293,14 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime); go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99' AS datetime2) AS datetimeoffset); @@ -314,7 +314,7 @@ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS datetime2 go ~~START~~ datetime2 -1900-05-06 21:59:29.9980000 +1900-05-06 13:59:29.9980000 ~~END~~ @@ -381,7 +381,7 @@ select CAST(CAST('1900-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ select CAST(CAST('1920-05-25 00:59:29.99 +0' AS datetimeoffset) AS time); @@ -416,7 +416,7 @@ select CAST(CAST('2050-05-06 23:59:29.998+8:00' AS datetimeoffset) AS time); go ~~START~~ time -15:59:29.9980000 +23:59:29.9980000 ~~END~~ @@ -425,21 +425,21 @@ select CAST(CAST('2000-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS smalldate go ~~START~~ smalldatetime -2000-06-07 09:29:00.0 +2000-06-06 23:59:00.0 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -2079-06-06 15:59:00.0 +2079-06-06 23:59:00.0 ~~END~~ select CAST(CAST('1900-05-06 13:59:29.998 -8:00' AS datetimeoffset) AS smalldatetime); go ~~START~~ smalldatetime -1900-05-06 21:59:00.0 +1900-05-06 13:59:00.0 ~~END~~ select CAST(CAST('2020-03-15 23:59:29.99' AS smalldatetime) AS datetimeoffset); diff --git a/test/JDBC/expected/latest__verification_cleanup__14_3__babel_datetime-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_3__babel_datetime-vu-verify.out index beb8038af8..4107ba9510 100644 --- a/test/JDBC/expected/latest__verification_cleanup__14_3__babel_datetime-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__14_3__babel_datetime-vu-verify.out @@ -194,21 +194,21 @@ select CAST(CAST('2079-06-06 23:59:29.998 +8:00' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-06 15:59:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:29.998 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:29.997 +2079-06-06 23:59:29.997 ~~END~~ select CAST(CAST('2079-06-06 23:59:12.345678 -9:30' AS datetimeoffset) AS datetime) go ~~START~~ datetime -2079-06-07 09:29:12.347 +2079-06-06 23:59:12.347 ~~END~~ -- out of range @@ -377,7 +377,7 @@ select dateadd(year, 150, cast('9900-12-26 23:29:29' as datetime)) go ~~ERROR (Code: 517)~~ -~~ERROR (Message: data out of range for datetime)~~ +~~ERROR (Message: Adding a value to a 'datetime' column caused an overflow.)~~ -- Test data type precedence TODO Fix [BABEL-883] missing TDS support for type regtype (was pg_typeof produces error in sqlcmd) diff --git a/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-cleanup.out index 12eb4ec818..6b112cb429 100644 --- a/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-cleanup.out +++ b/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-cleanup.out @@ -4,6 +4,9 @@ GO DROP VIEW isc_columns_vu_prepare_v1 GO +DROP VIEW isc_columns_bytea_v2 +GO + DROP FUNCTION isc_columns_vu_prepare_f2 DROP FUNCTION isc_columns_vu_prepare_f1 GO @@ -19,4 +22,5 @@ GO DROP TABLE isc_columns_vu_prepare_var DROP TABLE isc_columns_vu_prepare_dates DROP TABLE isc_columns_vu_prepare_nums +DROP TABLE isc_columns_vu_prepare_bytea GO diff --git a/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-verify.out index e64bee2b3d..04446793cb 100644 --- a/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-verify.out +++ b/test/JDBC/expected/latest__verification_cleanup__14_5__ISC-Columns-vu-verify.out @@ -23,15 +23,17 @@ SELECT * FROM information_schema.columns WHERE TABLE_NAME LIKE '%ISC_COLUMNS_VU_ 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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -76,15 +78,17 @@ master#!#dbo#!#isc_columns_vu_prepare_var#!#j#!#10#!##!#YES#!#xml#!#-1#!#- ~~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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -141,20 +145,22 @@ EXEC isc_columns_vu_prepare_p1 GO ~~START~~ int -49 +51 ~~END~~ ~~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#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!##!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#d#!#4#!##!#YES#!#bigint#!##!##!#19#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#h#!#8#!##!#YES#!#binary#!#9#!#9#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#e#!#5#!##!#YES#!#bit#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#a#!#1#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#a#!#1#!##!#YES#!#char#!#10#!#10#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_v1#!#IS_NULLABLE#!#7#!##!#YES#!#character varying#!##!##!##!##!##!##!##!##!##!##!##!#default#!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#a#!#1#!##!#YES#!#date#!##!##!##!##!##!#0#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#c#!#3#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_dates#!#d#!#4#!##!#YES#!#datetime2#!##!##!##!##!##!#5#!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#f#!#6#!##!#YES#!#float#!##!##!#53#!#2#!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_var#!#i#!#9#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_nums#!#a#!#1#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# master#!#dbo#!#isc_columns_vu_prepare_v1#!#CHARACTER_MAXIMUM_LENGTH#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# @@ -203,7 +209,7 @@ SELECT * FROM isc_columns_vu_prepare_f2() GO ~~START~~ int -49 +51 ~~END~~ ~~START~~ @@ -228,3 +234,11 @@ master#!#dbo#!#isc_columns_udt#!#b#!#2#!##!#YES#!#varchar#!#10#!#10#!##!#YES#!#bytea#!##!##!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#isc_columns_vu_prepare_bytea#!#b#!#2#!##!#YES#!#image#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!##!##!##!# +~~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_6__Test_ISNULL-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_6__Test_ISNULL-vu-cleanup.out new file mode 100644 index 0000000000..161ac422ed --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_6__Test_ISNULL-vu-cleanup.out @@ -0,0 +1,32 @@ +DROP FUNCTION [dbo].[test_isnull_func1]; +GO + +DROP FUNCTION [dbo].[test_isnull_func2]; +GO + +DROP PROCEDURE [dbo].[test_isnull_proc1]; +GO + +DROP VIEW [dbo].[test_isnull_view] +GO + +DROP VIEW [dbo].[test_isnull_view1] +GO + +DROP VIEW [dbo].[test_isnull_view2] +GO + +DROP VIEW [dbo].[test_isnull_view3] +GO + +DROP VIEW [dbo].[test_isnull_view4] +GO + +DROP VIEW [dbo].[test_isnull_view5] +GO + +DROP VIEW [dbo].[test_isnull_view7] +GO + +DROP TABLE [dbo].[test_isnull_table] +GO diff --git a/test/JDBC/expected/latest__verification_cleanup__14_6__Test_ISNULL-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_6__Test_ISNULL-vu-verify.out new file mode 100644 index 0000000000..4e04bc8de0 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_6__Test_ISNULL-vu-verify.out @@ -0,0 +1,181 @@ +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + name = 'my_computed_column' and + object_id = + ( + select object_id from sys.tables where name = 'test_isnull_table' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +bigint +~~END~~ + + +select * from [dbo].[test_isnull_table] +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +2#!##!#2 +~~END~~ + + +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +#!#Unassigned#!#Unassigned#!#Unassigned#!# +~~END~~ + + +select * from [dbo].[test_isnull_view]; +GO +~~START~~ +bigint +1 +2 +~~END~~ + + +select * from [dbo].[test_isnull_view1]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view2]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view3]; +GO +~~START~~ +int + +~~END~~ + + +select * from [dbo].[test_isnull_view4]; +GO +~~START~~ +text +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view5]; +GO +~~START~~ +varchar +1 +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view7]; +GO +~~START~~ +int +0 +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view3' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view4' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +text +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view5' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view7' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select [dbo].[test_isnull_func1](); +GO +~~START~~ +bigint +1 +~~END~~ + + +select [dbo].[test_isnull_func2]('1', 1); +GO +~~START~~ +bigint +1 +~~END~~ + + +exec [dbo].[test_isnull_proc1]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +~~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__14_9__BABEL-2877-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_9__BABEL-2877-vu-cleanup.out new file mode 100644 index 0000000000..2b3ac2c392 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_9__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_9__BABEL-2877-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_9__BABEL-2877-vu-verify.out new file mode 100644 index 0000000000..5970f8ab19 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_9__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_9__Test-sp_babelfish_volatility-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_9__Test-sp_babelfish_volatility-vu-cleanup.out new file mode 100644 index 0000000000..80a368ffa7 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_9__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_9__Test-sp_babelfish_volatility-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_9__Test-sp_babelfish_volatility-vu-verify.out new file mode 100644 index 0000000000..566b7301e4 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_9__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_9__Test_ISNULL-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__14_9__Test_ISNULL-vu-cleanup.out new file mode 100644 index 0000000000..161ac422ed --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_9__Test_ISNULL-vu-cleanup.out @@ -0,0 +1,32 @@ +DROP FUNCTION [dbo].[test_isnull_func1]; +GO + +DROP FUNCTION [dbo].[test_isnull_func2]; +GO + +DROP PROCEDURE [dbo].[test_isnull_proc1]; +GO + +DROP VIEW [dbo].[test_isnull_view] +GO + +DROP VIEW [dbo].[test_isnull_view1] +GO + +DROP VIEW [dbo].[test_isnull_view2] +GO + +DROP VIEW [dbo].[test_isnull_view3] +GO + +DROP VIEW [dbo].[test_isnull_view4] +GO + +DROP VIEW [dbo].[test_isnull_view5] +GO + +DROP VIEW [dbo].[test_isnull_view7] +GO + +DROP TABLE [dbo].[test_isnull_table] +GO diff --git a/test/JDBC/expected/latest__verification_cleanup__14_9__Test_ISNULL-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__14_9__Test_ISNULL-vu-verify.out new file mode 100644 index 0000000000..4e04bc8de0 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__14_9__Test_ISNULL-vu-verify.out @@ -0,0 +1,181 @@ +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + name = 'my_computed_column' and + object_id = + ( + select object_id from sys.tables where name = 'test_isnull_table' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +bigint +~~END~~ + + +select * from [dbo].[test_isnull_table] +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +2#!##!#2 +~~END~~ + + +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +#!#Unassigned#!#Unassigned#!#Unassigned#!# +~~END~~ + + +select * from [dbo].[test_isnull_view]; +GO +~~START~~ +bigint +1 +2 +~~END~~ + + +select * from [dbo].[test_isnull_view1]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view2]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view3]; +GO +~~START~~ +int + +~~END~~ + + +select * from [dbo].[test_isnull_view4]; +GO +~~START~~ +text +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view5]; +GO +~~START~~ +varchar +1 +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view7]; +GO +~~START~~ +int +0 +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view3' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view4' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +text +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view5' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view7' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select [dbo].[test_isnull_func1](); +GO +~~START~~ +bigint +1 +~~END~~ + + +select [dbo].[test_isnull_func2]('1', 1); +GO +~~START~~ +bigint +1 +~~END~~ + + +exec [dbo].[test_isnull_proc1]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +~~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/expected/latest__verification_cleanup__15_2__Test_ISNULL-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__15_2__Test_ISNULL-vu-cleanup.out new file mode 100644 index 0000000000..161ac422ed --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_2__Test_ISNULL-vu-cleanup.out @@ -0,0 +1,32 @@ +DROP FUNCTION [dbo].[test_isnull_func1]; +GO + +DROP FUNCTION [dbo].[test_isnull_func2]; +GO + +DROP PROCEDURE [dbo].[test_isnull_proc1]; +GO + +DROP VIEW [dbo].[test_isnull_view] +GO + +DROP VIEW [dbo].[test_isnull_view1] +GO + +DROP VIEW [dbo].[test_isnull_view2] +GO + +DROP VIEW [dbo].[test_isnull_view3] +GO + +DROP VIEW [dbo].[test_isnull_view4] +GO + +DROP VIEW [dbo].[test_isnull_view5] +GO + +DROP VIEW [dbo].[test_isnull_view7] +GO + +DROP TABLE [dbo].[test_isnull_table] +GO diff --git a/test/JDBC/expected/latest__verification_cleanup__15_2__Test_ISNULL-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__15_2__Test_ISNULL-vu-verify.out new file mode 100644 index 0000000000..4e04bc8de0 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_2__Test_ISNULL-vu-verify.out @@ -0,0 +1,181 @@ +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + name = 'my_computed_column' and + object_id = + ( + select object_id from sys.tables where name = 'test_isnull_table' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +bigint +~~END~~ + + +select * from [dbo].[test_isnull_table] +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +2#!##!#2 +~~END~~ + + +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +#!#Unassigned#!#Unassigned#!#Unassigned#!# +~~END~~ + + +select * from [dbo].[test_isnull_view]; +GO +~~START~~ +bigint +1 +2 +~~END~~ + + +select * from [dbo].[test_isnull_view1]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view2]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view3]; +GO +~~START~~ +int + +~~END~~ + + +select * from [dbo].[test_isnull_view4]; +GO +~~START~~ +text +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view5]; +GO +~~START~~ +varchar +1 +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view7]; +GO +~~START~~ +int +0 +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view3' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view4' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +text +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view5' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view7' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select [dbo].[test_isnull_func1](); +GO +~~START~~ +bigint +1 +~~END~~ + + +select [dbo].[test_isnull_func2]('1', 1); +GO +~~START~~ +bigint +1 +~~END~~ + + +exec [dbo].[test_isnull_proc1]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +~~END~~ + diff --git a/test/JDBC/expected/latest__verification_cleanup__15_4__Test_ISNULL-vu-cleanup.out b/test/JDBC/expected/latest__verification_cleanup__15_4__Test_ISNULL-vu-cleanup.out new file mode 100644 index 0000000000..161ac422ed --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_4__Test_ISNULL-vu-cleanup.out @@ -0,0 +1,32 @@ +DROP FUNCTION [dbo].[test_isnull_func1]; +GO + +DROP FUNCTION [dbo].[test_isnull_func2]; +GO + +DROP PROCEDURE [dbo].[test_isnull_proc1]; +GO + +DROP VIEW [dbo].[test_isnull_view] +GO + +DROP VIEW [dbo].[test_isnull_view1] +GO + +DROP VIEW [dbo].[test_isnull_view2] +GO + +DROP VIEW [dbo].[test_isnull_view3] +GO + +DROP VIEW [dbo].[test_isnull_view4] +GO + +DROP VIEW [dbo].[test_isnull_view5] +GO + +DROP VIEW [dbo].[test_isnull_view7] +GO + +DROP TABLE [dbo].[test_isnull_table] +GO diff --git a/test/JDBC/expected/latest__verification_cleanup__15_4__Test_ISNULL-vu-verify.out b/test/JDBC/expected/latest__verification_cleanup__15_4__Test_ISNULL-vu-verify.out new file mode 100644 index 0000000000..4e04bc8de0 --- /dev/null +++ b/test/JDBC/expected/latest__verification_cleanup__15_4__Test_ISNULL-vu-verify.out @@ -0,0 +1,181 @@ +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + name = 'my_computed_column' and + object_id = + ( + select object_id from sys.tables where name = 'test_isnull_table' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +bigint +~~END~~ + + +select * from [dbo].[test_isnull_table] +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +2#!##!#2 +~~END~~ + + +select + ISNULL(NULL, NULL), + ISNULL(NULL, 'Unassigned'), + ISNULL([my_varchar_data], 'Unassigned'), + ISNULL('Unassigned', 1), + ISNULL ('', 5) +from [dbo].[test_isnull_table]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +#!#Unassigned#!#Unassigned#!#Unassigned#!# +~~END~~ + + +select * from [dbo].[test_isnull_view]; +GO +~~START~~ +bigint +1 +2 +~~END~~ + + +select * from [dbo].[test_isnull_view1]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view2]; +GO +~~START~~ +bigint#!#varchar#!#bigint +1#!#1#!#1 +~~END~~ + + +select * from [dbo].[test_isnull_view3]; +GO +~~START~~ +int + +~~END~~ + + +select * from [dbo].[test_isnull_view4]; +GO +~~START~~ +text +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view5]; +GO +~~START~~ +varchar +1 +Unassigned +~~END~~ + + +select * from [dbo].[test_isnull_view7]; +GO +~~START~~ +int +0 +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view3' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view4' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +text +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view5' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +varchar +~~END~~ + + +select name from sys.types where system_type_id = +( + select system_type_id from sys.columns where + object_id = + ( + select object_id from sys.views where name = 'test_isnull_view7' + ) +) and is_user_defined = 0; +GO +~~START~~ +text +int +~~END~~ + + +select [dbo].[test_isnull_func1](); +GO +~~START~~ +bigint +1 +~~END~~ + + +select [dbo].[test_isnull_func2]('1', 1); +GO +~~START~~ +bigint +1 +~~END~~ + + +exec [dbo].[test_isnull_proc1]; +GO +~~START~~ +int#!#varchar#!#varchar#!#varchar#!#varchar +#!#Unassigned#!#1#!#Unassigned#!# +~~END~~ + diff --git a/test/JDBC/expected/like_expression.out b/test/JDBC/expected/like_expression.out new file mode 100644 index 0000000000..f6bcba192c --- /dev/null +++ b/test/JDBC/expected/like_expression.out @@ -0,0 +1,1374 @@ +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 '[%' -- suppose not having any result +GO +~~START~~ +varchar +~~END~~ + + +select * from t where a like '[c-a]bc' +GO +~~START~~ +varchar +~~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 +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#!#]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 + +DROP TABLE IF EXISTS t1 +GO +CREATE TABLE t1 +( + c1 int IDENTITY(1, 1) +,string varchar(20) null +,patt varchar(20) null +,esc varchar(2) null +) +go +insert t1 values +(null,null,null), +('ABCD', 'AB[C]D', 'X'), +('ABCD', 'ABcD', null), +('AB[C]D', 'ABZ[C]D', 'Z'), +('AB[C]D', 'ABZ[C]D', 'z') +go +~~ROW COUNT: 5~~ + +-- returns 2,3,4 , babel return 2,4 BABEL-4271 +select c1 from t1 where string like patt escape esc +and c1 > 1 order by c1 +go +~~START~~ +int +2 +4 +~~END~~ + + +DROP TABLE IF EXISTS t1 +GO +CREATE TABLE t1 +( + c1 int IDENTITY(1, 1) +,string varchar(50) +) +GO + + +--Note: we rely on identity value being generated sequentially +--from 1 in same order as the values in INSERT +INSERT INTO t1 (string) +VALUES + ('451201-7825') +,('451201x7825') +,('Andersson') +,('Bertilsson') +,('Carlson') +,('Davidsson') +,('Eriksson') +,('Fredriksson') +,('F') +,('F.') +,('Göransson') +,('Karlsson') +,('KarlsTon') +,('Karlson') +,('Persson') +,('Uarlson') +,('McDonalds') +,('MacDonalds') +,('15% off') +,('15 % off') +,('15 %off') +,('15 %') +,('15 % /off') +,('My[String') +,('My]String') +,('My[]String') +,('My][String') +,('My[valid]String') +--Swedish person-nummer(nnnnnn-nnnn); should return rows 1 +SELECT * FROM t1 WHERE string LIKE '[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]' +go +~~ROW COUNT: 28~~ + +~~START~~ +int#!#varchar +1#!#451201-7825 +~~END~~ + + +--As above, using REPLICATE; should return rows 1 +SELECT * FROM t1 WHERE string LIKE REPLICATE('[0-9]', 6) + '-' + REPLICATE('[0-9]', 4) +go +~~START~~ +int#!#varchar +1#!#451201-7825 +~~END~~ + + +--First 6 characters are numbers, using REPLICATE; should return rows 1 and 2 +SELECT * FROM t1 WHERE SUBSTRING(string, 1, 6) LIKE REPLICATE('[0-9]', 6) +go +~~START~~ +int#!#varchar +1#!#451201-7825 +2#!#451201x7825 +~~END~~ + + +--Enumeration, all Karlsson with C or K, one or two s should return rows: 5, 12, 14 +SELECT * FROM t1 WHERE string LIKE '[CK]arlson' OR string LIKE '[CK]arlsson' +go +~~START~~ +int#!#varchar +5#!#Carlson +12#!#Karlsson +14#!#Karlson +~~END~~ + + +--Negative enumeration, all Karlson except those with C or K; should return rows: 16 +SELECT * FROM t1 WHERE string LIKE '[^CK]arlson' +go +~~START~~ +int#!#varchar +16#!#Uarlson +~~END~~ + + +--Starts in range A-F; should return rows 3-10 +SELECT * FROM t1 WHERE string LIKE '[A-F]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +3#!#Andersson +4#!#Bertilsson +5#!#Carlson +6#!#Davidsson +7#!#Eriksson +8#!#Fredriksson +9#!#F +10#!#F. +~~END~~ + + +--Two ranges, A-B and E-G; should return rows 3-4, 7-11 +SELECT * FROM t1 WHERE string LIKE '[A-BE-G]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +3#!#Andersson +4#!#Bertilsson +7#!#Eriksson +8#!#Fredriksson +9#!#F +10#!#F. +11#!#Göransson +~~END~~ + + +--Starts in range A-C and also starting with E and G; should return rows 3, 4, 5, 7, 11 +SELECT * FROM t1 WHERE string LIKE '[A-CEG]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +3#!#Andersson +4#!#Bertilsson +5#!#Carlson +7#!#Eriksson +11#!#Göransson +~~END~~ + + +--All Donalds starting with M, exclude following c; should return rows 18 +SELECT * FROM t1 WHERE string LIKE 'M[^c]%Donalds' ORDER BY c1 +go +~~START~~ +int#!#varchar +18#!#MacDonalds +~~END~~ + + +--15% off using ESCAPE; should return rows 19 +SELECT * FROM t1 WHERE string LIKE '15/% %' ESCAPE '/' ORDER BY c1 +go +~~START~~ +int#!#varchar +19#!#15% off +~~END~~ + + +--15% off using a different ESCAPE character; should return rows 19 +SELECT * FROM t1 WHERE string LIKE '15!% %' ESCAPE '!' ORDER BY c1 +go +~~START~~ +int#!#varchar +19#!#15% off +~~END~~ + + +--15% off using square brackets; should return rows 19 +SELECT * FROM t1 WHERE string LIKE '15[%] %' ORDER BY c1 +go +~~START~~ +int#!#varchar +19#!#15% off +~~END~~ + + +--15 % off ; should return rows 21 +SELECT * FROM t1 WHERE string LIKE '15 /%___' ESCAPE '/' ORDER BY c1 +go +~~START~~ +int#!#varchar +21#!#15 %off +~~END~~ + + +--Searching for the escape character itself; should return rows 23 +SELECT * FROM t1 WHERE string LIKE '15 [%] //off' ESCAPE '/' ORDER BY c1 +go +~~START~~ +int#!#varchar +23#!#15 % /off +~~END~~ + + +--Contains [; should return rows 24, 26, 27, 28 +SELECT * FROM t1 WHERE string LIKE '%[[]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +24#!#My[String +26#!#My[]String +27#!#My][String +28#!#My[valid]String +~~END~~ + + +--Contains ]; should return rows 25, 26, 27, 28 +SELECT * FROM t1 WHERE string LIKE '%]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +25#!#My]String +26#!#My[]String +27#!#My][String +28#!#My[valid]String +~~END~~ + + +--As above, but allow "ö", should return same as above, except row 11 (Göransson) +SELECT * FROM t1 WHERE string LIKE '%[^a-zA-Z0-9öÖ]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +1#!#451201-7825 +10#!#F. +19#!#15% off +20#!#15 % off +21#!#15 %off +22#!#15 % +23#!#15 % /off +24#!#My[String +25#!#My]String +26#!#My[]String +27#!#My][String +28#!#My[valid]String +~~END~~ + + +--Negate above, and exclude the numbers, i.e. "only clean letters". Should return 3-9, 11-18 +SELECT * FROM t1 WHERE string NOT LIKE '%[^a-zA-ZåÅäÄöÖ]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +3#!#Andersson +4#!#Bertilsson +5#!#Carlson +6#!#Davidsson +7#!#Eriksson +8#!#Fredriksson +9#!#F +11#!#Göransson +12#!#Karlsson +13#!#KarlsTon +14#!#Karlson +15#!#Persson +16#!#Uarlson +17#!#McDonalds +18#!#MacDonalds +~~END~~ + + +--As above, but also allow for dot ".". Should return 3-18 +SELECT * FROM t1 WHERE string NOT LIKE '%[^a-zA-ZåÅäÄöÖ.]%' ORDER BY c1 +go +~~START~~ +int#!#varchar +3#!#Andersson +4#!#Bertilsson +5#!#Carlson +6#!#Davidsson +7#!#Eriksson +8#!#Fredriksson +9#!#F +10#!#F. +11#!#Göransson +12#!#Karlsson +13#!#KarlsTon +14#!#Karlson +15#!#Persson +16#!#Uarlson +17#!#McDonalds +18#!#MacDonalds +~~END~~ + + +--As above, but also allow for "[". Should return 3-18, 24 +SELECT * FROM t1 WHERE string NOT LIKE '%[^a-zA-ZåÅäÄöÖ.[?[]%' ESCAPE '?' ORDER BY c1 +go +~~START~~ +int#!#varchar +3#!#Andersson +4#!#Bertilsson +5#!#Carlson +6#!#Davidsson +7#!#Eriksson +8#!#Fredriksson +9#!#F +10#!#F. +11#!#Göransson +12#!#Karlsson +13#!#KarlsTon +14#!#Karlson +15#!#Persson +16#!#Uarlson +17#!#McDonalds +18#!#MacDonalds +24#!#My[String +~~END~~ + + + +--- test case with LIKE in a CHECK constraint ----------------- +DROP TABLE IF EXISTS t1 +GO +CREATE TABLE t1 +( + c1 int PRIMARY KEY +,pnr char(11) CHECK (pnr LIKE '[0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]') +) +GO +--Verify it does its job +INSERT INTO t1 (c1, pnr) VALUES(1, '451201-7825') --Should be OK +GO +~~ROW COUNT: 1~~ + +INSERT INTO t1 (c1, pnr) VALUES(1, '451d01-7825') --Should fail +GO +~~ERROR (Code: 547)~~ + +~~ERROR (Message: new row for relation "t1" violates check constraint "t1_pnr_check")~~ + +INSERT INTO t1 (c1, pnr) VALUES(1, '451201w7825') --Should fail +GO +~~ERROR (Code: 547)~~ + +~~ERROR (Message: new row for relation "t1" violates check constraint "t1_pnr_check")~~ + + +drop table t1; +GO + +DROP TABLE IF EXISTS IP_address +GO +CREATE TABLE IP_address +( + c1 int IDENTITY(1, 1) +,string varchar(50) +,is_valid bit +) +GO + +INSERT INTO IP_address (string, is_valid) +VALUES +--Valid: + ('131.107.2.201', 1) +,('131.33.2.201', 1) +,('131.33.2.202', 1) +,('3.107.2.4', 1) +,('3.107.3.169', 1) +,('3.107.104.172', 1) +,('22.107.202.123', 1) +,('22.20.2.77', 1) +,('22.156.9.91', 1) +,('22.156.89.32', 1) +--Not valid: +,('22.356.89.32', 0) +,('1.1.1.256', 0) +,('1.1.1.1.1', 0) +,('1.1.1', 0) +,('1..1.1', 0) +,('.1.1.1', 0) +,('a.1.1.1', 0) +go +~~ROW COUNT: 17~~ + + +SELECT * FROM IP_address +WHERE + -- 3 periods and no empty octets + string LIKE '_%._%._%._%' + AND + -- not 4 periods or more + string NOT LIKE '%.%.%.%.%' + AND + -- no characters other than digits and periods + string NOT LIKE '%[^0-9.]%' + AND + -- not more than 3 digits per octet + string NOT LIKE '%[0-9][0-9][0-9][0-9]%' + AND + -- NOT 300 - 999 + string NOT LIKE '%[3-9][0-9][0-9]%' + AND + -- NOT 260 - 299 + string NOT LIKE '%2[6-9][0-9]%' + AND + -- NOT 256 - 259 + string NOT LIKE '%25[6-9]%' +ORDER BY c1 +go +~~START~~ +int#!#varchar#!#bit +1#!#131.107.2.201#!#1 +2#!#131.33.2.201#!#1 +3#!#131.33.2.202#!#1 +4#!#3.107.2.4#!#1 +5#!#3.107.3.169#!#1 +6#!#3.107.104.172#!#1 +7#!#22.107.202.123#!#1 +8#!#22.20.2.77#!#1 +9#!#22.156.9.91#!#1 +10#!#22.156.89.32#!#1 +~~END~~ + + +--Negate the full above predicate; should return rows 11-17 +SELECT * FROM IP_address +WHERE NOT( + -- 3 periods and no empty octets + string LIKE '_%._%._%._%' + AND + -- not 4 periods or more + string NOT LIKE '%.%.%.%.%' + AND + -- no characters other than digits and periods + string NOT LIKE '%[^0-9.]%' + AND + -- not more than 3 digits per octet + string NOT LIKE '%[0-9][0-9][0-9][0-9]%' + AND + -- NOT 300 - 999 + string NOT LIKE '%[3-9][0-9][0-9]%' + AND + -- NOT 260 - 299 + string NOT LIKE '%2[6-9][0-9]%' + AND + -- NOT 256 - 259 + string NOT LIKE '%25[6-9]%') +ORDER BY c1 +go +~~START~~ +int#!#varchar#!#bit +11#!#22.356.89.32#!#0 +12#!#1.1.1.256#!#0 +13#!#1.1.1.1.1#!#0 +14#!#1.1.1#!#0 +15#!#1..1.1#!#0 +16#!#.1.1.1#!#0 +17#!#a.1.1.1#!#0 +~~END~~ + + +drop table IP_address +GO + +select 1 where '9' like '[a-z0-9]' -- 1 +GO +~~START~~ +int +1 +~~END~~ + + +select 1 where '9' like '[0-9' -- no row +GO +~~START~~ +int +~~END~~ + + +select 1 where 'b' like '[a-z0-9]' -- 1 +GO +~~START~~ +int +1 +~~END~~ + + +select 1 where '7' like '[^a-z0-9]' -- no row +GO +~~START~~ +int +~~END~~ + + +select 1 where 'D' like '[C-P5-7]' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'B' like '[C-P5-7]' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where 'B' like '[^C-P5-7]' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where '4' like '[C-P5-7]' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where '9' like '[C-P5-7]' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where '1357' like '[0-9][0-9][0-9][0-9]' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'a[abc]b' like 'a[abc]b' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where 'a[abc]b' like 'a[[]abc]b' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'a[abc]b' like 'a\[abc]b' escape '\' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'a[b' like 'a[%' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where 'a[b' like 'a[[]%' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where '$abc' like '[0-9!@#$.,;_]%' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where '$abc' like '[^0-9!@#$.,;_]%' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where '$abc' like '[^0-9!@#.,;_]%' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'abc_efgh' like 'abc[_]efg%' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'abcdefgh' like 'abc[_]efg%' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where 'abcdefgh' like 'abc[^_]efg%' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'd' like '[asdf]' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'e' like '[asdf]' -- no row +go +~~START~~ +int +~~END~~ + + +select 1 where 'e' like '[^asdf]' -- 1 +go +~~START~~ +int +1 +~~END~~ + + +select 1 where 'd' like '[^asdf]' -- no row +go +~~START~~ +int +~~END~~ + + +declare @v varchar = 'a[bc' +SELECT 1 where @v LIKE '%[%' escape '~' OR @v LIKE '%]%' -- no row +go +~~START~~ +int +~~END~~ + + +declare @v varchar = 'a[bc' +SELECT 1 where @v LIKE '%[[]%' OR @v LIKE '%[]]%' -- no row +go +~~START~~ +int +~~END~~ + + +declare @v varchar = 'a[bc' +SELECT 1 where @v LIKE '%~[%' escape '~' OR @v LIKE '%~]%' escape '~' -- no row +GO +~~START~~ +int +~~END~~ + + +declare @v varchar = 'a[bc' +set @v = 'a]bc' +SELECT 1 where @v LIKE '%[%' escape '~' OR @v LIKE '%]%' -- no row +go +~~START~~ +int +~~END~~ + + +declare @v varchar = 'a[bc' +set @v = 'a]bc' +SELECT 1 where @v LIKE '%[[]%' OR @v LIKE '%[]]%' -- no row +go +~~START~~ +int +~~END~~ + + +declare @v varchar = 'a[bc' +set @v = 'a]bc' +SELECT 1 where @v LIKE '%~[%' escape '~' OR @v LIKE '%~]%' escape '~' -- no row +go +~~START~~ +int +~~END~~ + + + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '9'set @p = '[a-z0-9]' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '9'set @p = '[0-9' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'b'set @p = '[a-z0-9]' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '7'set @p = '[^a-z0-9]' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'D'set @p = '[C-P5-7]' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'B'set @p = '[C-P5-7]' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'B'set @p = '[^C-P5-7]' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '4'set @p = '[C-P5-7]' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '9'set @p = '[C-P5-7]' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'a[abc]b'set @p = 'a[abc]b' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'a[abc]b'set @p = 'a[[]abc]b' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'a[abc]b'set @p = 'a\[abc]b' set @esc = '\' -- 1 +select 1 where @v like @p escape @esc +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'a[b'set @p = 'a[%' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'a[b'set @p = 'a[[]%' -- 1 +select 1 where @v like @p +GO +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '$abc'set @p = '[0-9!@#$.,;_]%' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = '$abc'set @p = '[^0-9!@#$.,;_]%' -- no row +select 1 where @v like @p +GO +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'abc_efgh' set @p = 'abc[_]efg%' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'abcdefgh' set @p = 'abc[_]efg%' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'abcdefgh' set @p = 'abc[^_]efg%' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'd' set @p = '[asdf]' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'e' set @p = '[asdf]' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'e' set @p = '[^asdf]' -- 1 +select 1 where @v like @p +go +~~START~~ +int +1 +~~END~~ + + +declare @v varchar(20), @p varchar(20), @esc char(1) +set @v = 'd' set @p = '[^asdf]' -- no row +select 1 where @v like @p +go +~~START~~ +int +~~END~~ + + +-- the following currently returns wrong result in BBF! +select 1 where '_ab' like '\_ab' -- no row, but returns 1 in BBF , BABEL-4270 +GO +~~START~~ +int +~~END~~ + + +select 1 where '%AAABBB%' like '\%AAA%' -- no row, but returns 1 in BBF , BABEL-4270 +go +~~START~~ +int +~~END~~ + + +select 1 where '_ab' like '\_ab' escape '\' -- 1 +select 1 where '%AAABBB%' like '\%AAA%' escape '\' -- 1 +go +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +select 1 where 'AB[C]D' LIKE 'AB~[C]D' -- no row +select 1 where 'AB[C]D' LIKE 'AB~[C]D' ESCAPE '~' -- 1 +go +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +select 1 where 'AB[C]D' LIKE 'AB\[C]D' -- no row +select 1 where 'AB[C]D' LIKE 'AB\[C]D' ESCAPE '\' -- 1 +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +select 1 where 'AB[C]D' LIKE 'AB [C]D' -- no row +select 1 where 'AB[C]D' LIKE 'AB [C]D' ESCAPE ' ' -- 1 +GO +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +select 1 where 'AB[C]D' LIKE 'AB[C]D' ESCAPE 'B' -- no row +select 1 where 'AB[C]D' LIKE 'ABB[C]D' ESCAPE 'B' -- no row +go +~~START~~ +int +~~END~~ + +~~START~~ +int +~~END~~ + + +select 1 where 'AB[C]D' LIKE 'ABZ[C]D' ESCAPE 'Z' -- 1 +select 1 where 'AB[C]D' LIKE 'ABZ[C]D' ESCAPE 'z' -- no row! Note: SQL Server treats the escape as case-sensitive! +select 1 where 'ABCD' LIKE 'ABcD' -- 1 : SQL Server treats normal LIKE pattern case-INsensitive +go +~~START~~ +int +1 +~~END~~ + +~~START~~ +int +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +select 1 where null like null -- no row +go +~~START~~ +int +~~END~~ + +select 1 where null like null escape null -- no row +go +~~START~~ +int +~~END~~ + +select 1 where null like 'ABC' -- no row +go +~~START~~ +int +~~END~~ + +select 1 where 'ABC' like null -- no row +go +~~START~~ +int +~~END~~ + + + +select 1 where 'ABCD' LIKE 'AB[C]D' ESCAPE '' -- should raise error , BABEL-4271 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The invalid escape character "" was specified in a LIKE predicate.)~~ + +select 1 where 'ABCD' LIKE 'AB[C]D' ESCAPE 'xy' -- raise error +go +~~ERROR (Code: 506)~~ + +~~ERROR (Message: invalid escape string)~~ + + +create table tt ( a bytea); +go + +insert into tt values (0xdaa) +GO +~~ROW COUNT: 1~~ + + +select * from tt where a like 'da[%]'; +GO +~~START~~ +varbinary +~~END~~ + + +select * from tt where a not like 'da[%]'; +go +~~START~~ +varbinary +0DAA +~~END~~ + + +drop table tt; +GO diff --git a/test/JDBC/expected/linked_servers-vu-cleanup.out b/test/JDBC/expected/linked_servers-vu-cleanup.out index 0bfb6e60a8..6efce4b4ea 100644 --- a/test/JDBC/expected/linked_servers-vu-cleanup.out +++ b/test/JDBC/expected/linked_servers-vu-cleanup.out @@ -17,7 +17,7 @@ GO DO $$ BEGIN -IF NOT EXISTS (SELECT * FROM pg_user_mappings WHERE srvname = 'bbf_server') THEN +IF NOT EXISTS (SELECT * FROM pg_user_mappings WHERE srvname = 'bbf_server' OR srvname = 'server_4229') THEN SET client_min_messages = 'error'; DROP EXTENSION tds_fdw CASCADE; END IF; diff --git a/test/JDBC/expected/linked_servers-vu-prepare.out b/test/JDBC/expected/linked_servers-vu-prepare.out index dc1036191b..8af9ef35ae 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 @@ -105,14 +113,6 @@ GO EXEC sp_addlinkedsrvlogin @rmtsrvname = 'mssql_server2', @useself = 'FALSE', @rmtuser = 'only_user_no_password' GO ---Try to add a linked server login with same server name but different case (should throw an error) -EXEC sp_addlinkedsrvlogin @rmtsrvname = 'MSSQL_server2', @useself = 'FALSE', @rmtuser = 'only_user_no_password' -GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: user mapping for "master_dbo" already exists for server "mssql_server2")~~ - - -- Create a linked server login with no @rmtuser (Won't throw error at creation time but will most likely fail remote login attempt) EXEC sp_addlinkedsrvlogin @rmtsrvname = 'mssql_server3', @useself = 'FALSE', @rmtpassword = 'only_password_no_user' GO @@ -125,19 +125,19 @@ GO CREATE FUNCTION sys_linked_servers_vu_prepare__sys_servers_func() RETURNS TABLE AS -RETURN (SELECT name, product, provider, data_source, provider_string, catalog, is_linked FROM sys.servers WHERE name <> 'bbf_server' ORDER BY name); +RETURN (SELECT name, product, provider, data_source, provider_string, catalog, is_linked FROM sys.servers WHERE name NOT LIKE 'bbf_server%' AND name NOT LIKE 'server_4229%' ORDER BY name); GO -- Create a view dependent on sys.servers view CREATE VIEW sys_linked_servers_vu_prepare__sys_servers_view AS -SELECT name, product, provider, data_source, provider_string, catalog, is_linked FROM sys.servers WHERE name <> 'bbf_server' ORDER BY name +SELECT name, product, provider, data_source, provider_string, catalog, is_linked FROM sys.servers WHERE name NOT LIKE 'bbf_server%' AND name NOT LIKE 'server_4229%' ORDER BY name GO -- Create a view dependent on sys.linked_logins view CREATE VIEW sys_linked_servers_vu_prepare__sys_linked_logins_view AS -SELECT s.name as linked_srv_name, l.remote_name as username FROM sys.servers as s INNER JOIN sys.linked_logins as l on s.server_id = l.server_id WHERE name <> 'bbf_server' ORDER BY linked_srv_name +SELECT s.name as linked_srv_name, l.remote_name as username FROM sys.servers as s INNER JOIN sys.linked_logins as l on s.server_id = l.server_id WHERE name NOT LIKE 'bbf_server%' AND name NOT LIKE 'server_4229%' ORDER BY linked_srv_name GO -- tsql user=linked_server_login_861 password=password_861 diff --git a/test/JDBC/expected/linked_servers-vu-verify.out b/test/JDBC/expected/linked_servers-vu-verify.out index 7edff2ab16..c95bac03a3 100644 --- a/test/JDBC/expected/linked_servers-vu-verify.out +++ b/test/JDBC/expected/linked_servers-vu-verify.out @@ -1,5 +1,5 @@ -- Check if the linked server added is reflected in the system view -SELECT name, product, provider, data_source, provider_string, catalog, is_linked FROM sys.servers WHERE name <> 'bbf_server' ORDER BY name +SELECT name, product, provider, data_source, provider_string, catalog, is_linked FROM sys.servers WHERE name NOT LIKE 'bbf_server%' AND name NOT LIKE 'server_4229%' ORDER BY name GO ~~START~~ varchar#!#varchar#!#varchar#!#nvarchar#!#nvarchar#!#varchar#!#bit @@ -35,7 +35,7 @@ mssql_server3#!##!#tds_fdw#!#mssql_server2\ABC#!##!#master#!#1 ~~END~~ -SELECT s.name as linked_srv_name, l.remote_name as username FROM sys.servers as s INNER JOIN sys.linked_logins as l on s.server_id = l.server_id WHERE s.name <> 'bbf_server' ORDER BY linked_srv_name +SELECT s.name as linked_srv_name, l.remote_name as username FROM sys.servers as s INNER JOIN sys.linked_logins as l on s.server_id = l.server_id WHERE s.name NOT LIKE 'bbf_server%' AND s.name NOT LIKE 'server_4229%' ORDER BY linked_srv_name GO ~~START~~ varchar#!#varchar @@ -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 NOT LIKE 'bbf_server%' AND a NOT LIKE 'server_4229%' 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 NOT LIKE 'bbf_server%' AND a NOT LIKE 'server_4229%' ORDER BY a SET NOCOUNT OFF GO ~~START~~ @@ -156,7 +156,16 @@ GO EXEC sp_droplinkedsrvlogin @rmtsrvname = "MSSQL_server2", @locallogin = NULL GO -EXEC sp_droplinkedsrvlogin @rmtsrvname = "mssql_server3", @locallogin = NULL +-- leading spaces are not ignored (should throw error) +EXEC sp_droplinkedsrvlogin @rmtsrvname = " mssql_server3", @locallogin = NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server " mssql_server3" does not exist)~~ + + +-- trailing spaces are ignored +EXEC sp_droplinkedsrvlogin @rmtsrvname = "mssql_server3 ", @locallogin = NULL GO -- Call sp_droplinkedsrvlogin from master.dbo schema @@ -221,3 +230,151 @@ GO varchar#!#varchar ~~END~~ + +-- Testing the sp_testlinkedserver stored procedure with NULL servername argument (should throw error) +EXEC sp_testlinkedserver NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @servername parameter cannot be NULL)~~ + + +-- Testing the sp_testlinkedserver stored procedure with servername argument whose length is more than 128 chars (should throw error) +EXEC sp_testlinkedserver 'LjW4d3W5DcAMPlqprZ3jhgYfKbU1e8nV20ovRmJH7kbv9iXq4SNlTIQxAloKOze1f2tsnPLRu9BFyUgQYvKLpN3CBNTZP4zIZT4koPloGBYhWvg2c0qD6nM5aChQolTmzq32yGFAgXaj5rdxOXTSNwTIjxGZTVzhr39EhObE3k2DHExzS5Wg6SE1ZFLIjVJWlxibh7Xa8OzU0xQrI1VdmVuPS9vllwTQfNRzxv2etZXJdfVgR2p9bMkprV7SZtcP97bDluDk3hqV0D8Qy0U2LsdAMbHwPb5m6SE2n0seInwq2t4sN' +GO +~~ERROR (Code: 8152)~~ + +~~ERROR (Message: value too long for type character varying(128))~~ + + +-- Testing the connection to a linked server using a server name that does not exist (should throw error) +IF EXISTS(SELECT * FROM sys.servers WHERE name = 'test_server') + EXEC sp_dropserver 'test_server', 'droplogins' +GO + +EXEC sp_testlinkedserver 'test_server' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server "test_server" does not exist)~~ + + +-- Testing the connection to a existing linked server using the server name with leading spaces (should throw error) +EXEC sp_addlinkedserver @server = N'test_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +EXEC sp_testlinkedserver ' test_server' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server " test_server" does not exist)~~ + + +-- Testing the connection to a existing linked server using the server name with mixed spaces (should throw error) +EXEC sp_testlinkedserver ' test_server ' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: server " test_server" does not exist)~~ + + +-- Tesing the connection to a linked server for which user mapping does not exist (should throw error) +EXEC sp_testlinkedserver 'test_server' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: user mapping not found for "master_dbo")~~ + + +EXEC sp_dropserver @server = 'test_server', @droplogins = 'droplogins' +GO + +-- Testing the connection to a linked server whose data source is incorrect (should throw error) +EXEC sp_addlinkedserver @server = N'test_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhos', @catalog=N'master' +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'test_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +EXEC sp_testlinkedserver 'test_server' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: DB #: 20012, DB Msg: server name not found in configuration files, OS #: 0, OS Msg: Success, Level: 2)~~ + + +EXEC sp_dropserver @server = 'test_server', @droplogins = 'droplogins' +GO + +-- Testing the connection to a linked server whose catalog name is incorrect (should throw error) +EXEC sp_addlinkedserver @server = N'test_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'maste' +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'test_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +EXEC sp_testlinkedserver 'test_server' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: Msg #: 911, Msg state: 1, Msg: database "maste" does not exist, Server: BABELFISH, Process: , Line: 1, Level: 16)~~ + + +EXEC sp_dropserver @server = 'test_server', @droplogins = 'droplogins' +GO + +-- Testing the connection to a linked server whose all parameters has been set correctly (should pass) +EXEC sp_addlinkedserver @server = N'test_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'test_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +EXEC sp_testlinkedserver 'test_server' +GO + +-- Testing the connection to a right linked server with trailing spaces in the servername argument (should pass) +EXEC sp_testlinkedserver 'test_server ' +GO + +-- Testing the connection to a right linked server with double-quoted(delimiter) servername argument (should pass) +EXEC sp_testlinkedserver "test_server" +GO + +-- Testing the connection to a right linked server with master.dbo prefix to stored procedure (should pass) +EXEC master.dbo.sp_testlinkedserver 'test_server' +GO + +-- Testing the connection to a right linked server without the EXEC keyword (should pass) +sp_testlinkedserver 'test_server' +GO + +EXEC sp_dropserver @server = 'test_server', @droplogins = 'droplogins' +GO + +-- Testing the stored procedure sp_enum_oledb_providers as a sysadmin user and with tds_fdw extension +EXEC sp_enum_oledb_providers +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +TDS_FDW#!#{f34cef3b-778b-23ac-4fff-7d01c089051e}#!#A PostgreSQL foreign data wrapper to connect to TDS databases 2.0.3 +~~END~~ + + +-- Testing the stored procedure sp_enum_oledb_providers with master.dbo prefix +EXEC master.dbo.sp_enum_oledb_providers +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +TDS_FDW#!#{f34cef3b-778b-23ac-4fff-7d01c089051e}#!#A PostgreSQL foreign data wrapper to connect to TDS databases 2.0.3 +~~END~~ + + +-- Testing the stored procedure sp_enum_oledb_providers with master.sys prefix +EXEC master.sys.sp_enum_oledb_providers +GO +~~START~~ +nvarchar#!#nvarchar#!#nvarchar +TDS_FDW#!#{f34cef3b-778b-23ac-4fff-7d01c089051e}#!#A PostgreSQL foreign data wrapper to connect to TDS databases 2.0.3 +~~END~~ + diff --git a/test/JDBC/expected/linked_srv_4229-vu-cleanup.out b/test/JDBC/expected/linked_srv_4229-vu-cleanup.out new file mode 100644 index 0000000000..d015d62376 --- /dev/null +++ b/test/JDBC/expected/linked_srv_4229-vu-cleanup.out @@ -0,0 +1,17 @@ +EXEC sp_dropserver 'server_4229', 'droplogins' +GO + +-- psql +-- Drop extension only if not user mapping exists for bbf_server +-- Needed so that same test can be reused in upgrade in conjunction +-- with tests for OPENQUERY +DO +$$ +BEGIN +IF NOT EXISTS (SELECT * FROM pg_user_mappings WHERE srvname = 'bbf_server') THEN + SET client_min_messages = 'error'; + DROP EXTENSION tds_fdw CASCADE; +END IF; +END +$$ +GO diff --git a/test/JDBC/expected/linked_srv_4229-vu-prepare.out b/test/JDBC/expected/linked_srv_4229-vu-prepare.out new file mode 100644 index 0000000000..e2d284052b --- /dev/null +++ b/test/JDBC/expected/linked_srv_4229-vu-prepare.out @@ -0,0 +1,13 @@ +-- psql +SET client_min_messages = 'error'; +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +-- Add localhost as linked server +EXEC sp_addlinkedserver @server = N'server_4229', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'server_4229', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO diff --git a/test/JDBC/expected/linked_srv_4229-vu-verify.out b/test/JDBC/expected/linked_srv_4229-vu-verify.out new file mode 100644 index 0000000000..d77eff5ba6 --- /dev/null +++ b/test/JDBC/expected/linked_srv_4229-vu-verify.out @@ -0,0 +1,69 @@ +-- Call OPENQUERY() / four-part-object name from a database other than master +USE tempdb +CREATE TABLE t_tempdb_babel_4229 (a int) +INSERT INTO t_tempdb_babel_4229 VALUES (42290) +SELECT * FROM OPENQUERY(server_4229, 'SELECT ''Called from tempdb''') +SELECT * FROM server_4229.tempdb.dbo.t_tempdb_babel_4229 +DROP TABLE t_tempdb_babel_4229 +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Changed database context to 'tempdb'. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Changed database context to 'tempdb'. Server SQLState: S0001)~~ + +~~START~~ +varchar +Called from tempdb +~~END~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Changed database context to 'tempdb'. Server SQLState: S0001)~~ + +~~START~~ +int +42290 +~~END~~ + + +CREATE DATABASE openquery_db +USE openquery_db +CREATE TABLE t_openquerydb_babel_4229 (b int) +INSERT INTO t_openquerydb_babel_4229 VALUES (42291) +SELECT * FROM OPENQUERY(server_4229, 'SELECT ''Called from openquery_db''') +SELECT * FROM server_4229.openquery_db.dbo.t_openquerydb_babel_4229 +DROP TABLE t_openquerydb_babel_4229 +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Changed database context to 'openquery_db'. Server SQLState: S0001)~~ + +~~ROW COUNT: 1~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Changed database context to 'openquery_db'. Server SQLState: S0001)~~ + +~~START~~ +varchar +Called from openquery_db +~~END~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: Changed database context to 'openquery_db'. Server SQLState: S0001)~~ + +~~START~~ +int +42291 +~~END~~ + + +USE master +DROP DATABASE openquery_db +GO diff --git a/test/JDBC/expected/master__preparation__BABEL-4206-vu-prepare.out b/test/JDBC/expected/master__preparation__BABEL-4206-vu-prepare.out new file mode 100644 index 0000000000..6eef2b5c5f --- /dev/null +++ b/test/JDBC/expected/master__preparation__BABEL-4206-vu-prepare.out @@ -0,0 +1,72 @@ +CREATE LOGIN babel_4206_vu_prepare_login1 WITH PASSWORD = 'abc'; +GO + +CREATE LOGIN babel_4206_vu_prepare_login2 WITH PASSWORD = 'abc'; +GO + +CREATE USER babel_4206_vu_prepare_user1 FOR LOGIN babel_4206_vu_prepare_login1; +GO + +CREATE USER babel_4206_vu_prepare_user2 FOR LOGIN babel_4206_vu_prepare_login2; +GO + +CREATE ROLE babel_4206_vu_prepare_role1; +GO + +CREATE ROLE babel_4206_vu_prepare_role2; +GO + +ALTER ROLE babel_4206_vu_prepare_role1 ADD MEMBER babel_4206_vu_prepare_role2; +GO + +ALTER ROLE babel_4206_vu_prepare_role1 ADD MEMBER babel_4206_vu_prepare_user1; +GO + +ALTER ROLE babel_4206_vu_prepare_role2 ADD MEMBER babel_4206_vu_prepare_user2; +GO + +CREATE PROC babel_4206_vu_prepare_user_ext AS +BEGIN + SELECT rolname, login_name, type, orig_username, database_name + FROM sys.babelfish_authid_user_ext + WHERE orig_username LIKE 'babel_4206_vu_prepare%' + ORDER BY rolname, orig_username +END +GO + +CREATE PROC babel_4206_vu_prepare_role_members AS +BEGIN + SELECT dp1.name AS RoleName, dp1.type AS RoleType, + dp2.name AS MemberName, dp2.type AS MemberType + FROM sys.database_role_members AS drm + INNER JOIN sys.database_principals AS dp1 + ON drm.role_principal_id = dp1.principal_id + INNER JOIN sys.database_principals AS dp2 + ON drm.member_principal_id = dp2.principal_id + WHERE dp1.name LIKE 'babel_4206_vu_prepare%' + ORDER BY dp1.name, dp2.name +END +GO + +-- show roles and users +EXEC babel_4206_vu_prepare_user_ext; +GO +~~START~~ +varchar#!#varchar#!#char#!#nvarchar#!#nvarchar +master_babel_4206_vu_prepare_role1#!##!#R#!#babel_4206_vu_prepare_role1#!#master +master_babel_4206_vu_prepare_role2#!##!#R#!#babel_4206_vu_prepare_role2#!#master +master_babel_4206_vu_prepare_user1#!#babel_4206_vu_prepare_login1#!#S#!#babel_4206_vu_prepare_user1#!#master +master_babel_4206_vu_prepare_user2#!#babel_4206_vu_prepare_login2#!#S#!#babel_4206_vu_prepare_user2#!#master +~~END~~ + + +-- show role membership +EXEC babel_4206_vu_prepare_role_members; +GO +~~START~~ +varchar#!#char#!#varchar#!#char +babel_4206_vu_prepare_role1#!#R#!#babel_4206_vu_prepare_role2#!#R +babel_4206_vu_prepare_role1#!#R#!#babel_4206_vu_prepare_user1#!#S +babel_4206_vu_prepare_role2#!#R#!#babel_4206_vu_prepare_user2#!#S +~~END~~ + diff --git a/test/JDBC/expected/master__verification_cleanup__BABEL-4206-vu-cleanup.out b/test/JDBC/expected/master__verification_cleanup__BABEL-4206-vu-cleanup.out new file mode 100644 index 0000000000..aed7c988f6 --- /dev/null +++ b/test/JDBC/expected/master__verification_cleanup__BABEL-4206-vu-cleanup.out @@ -0,0 +1,23 @@ +DROP USER babel_4206_vu_prepare_user1; +GO + +DROP USER babel_4206_vu_prepare_user2; +GO + +DROP ROLE babel_4206_vu_prepare_role2; +GO + +DROP ROLE babel_4206_vu_prepare_role1; +GO + +DROP LOGIN babel_4206_vu_prepare_login1; +GO + +DROP LOGIN babel_4206_vu_prepare_login2; +GO + +DROP PROCEDURE babel_4206_vu_prepare_user_ext; +GO + +DROP PROCEDURE babel_4206_vu_prepare_role_members; +GO diff --git a/test/JDBC/expected/master__verification_cleanup__BABEL-4206-vu-verify.out b/test/JDBC/expected/master__verification_cleanup__BABEL-4206-vu-verify.out new file mode 100644 index 0000000000..20652975e7 --- /dev/null +++ b/test/JDBC/expected/master__verification_cleanup__BABEL-4206-vu-verify.out @@ -0,0 +1,62 @@ +-- check roles and users +-- login_name should be empty after database-level restore +EXEC babel_4206_vu_prepare_user_ext; +GO +~~START~~ +varchar#!#varchar#!#char#!#nvarchar#!#nvarchar +master_babel_4206_vu_prepare_role1#!##!#R#!#babel_4206_vu_prepare_role1#!#master +master_babel_4206_vu_prepare_role2#!##!#R#!#babel_4206_vu_prepare_role2#!#master +master_babel_4206_vu_prepare_user1#!##!#S#!#babel_4206_vu_prepare_user1#!#master +master_babel_4206_vu_prepare_user2#!##!#S#!#babel_4206_vu_prepare_user2#!#master +~~END~~ + + +-- dbo and guest roles should be member of sysadmin +SELECT r.rolname FROM pg_catalog.pg_auth_members m + JOIN pg_catalog.pg_roles r + ON (m.roleid = r.oid) +WHERE m.member = (SELECT oid FROM pg_roles WHERE rolname = 'sysadmin') +AND r.rolname LIKE 'master_%' ORDER BY r.rolname; +GO +~~START~~ +varchar +master_dbo +master_guest +~~END~~ + + +-- check role membership is intact +EXEC babel_4206_vu_prepare_role_members; +GO +~~START~~ +varchar#!#char#!#varchar#!#char +babel_4206_vu_prepare_role1#!#R#!#babel_4206_vu_prepare_role2#!#R +babel_4206_vu_prepare_role1#!#R#!#babel_4206_vu_prepare_user1#!#S +babel_4206_vu_prepare_role2#!#R#!#babel_4206_vu_prepare_user2#!#S +~~END~~ + + +-- verify that users can be mapped to new logins +CREATE LOGIN babel_4206_vu_prepare_login1 WITH PASSWORD = 'abc'; +GO + +CREATE LOGIN babel_4206_vu_prepare_login2 WITH PASSWORD = 'abc'; +GO + +ALTER USER babel_4206_vu_prepare_user1 WITH LOGIN = babel_4206_vu_prepare_login1; +GO + +ALTER USER babel_4206_vu_prepare_user2 WITH LOGIN = babel_4206_vu_prepare_login2; +GO + +-- again check updated users +EXEC babel_4206_vu_prepare_user_ext; +GO +~~START~~ +varchar#!#varchar#!#char#!#nvarchar#!#nvarchar +master_babel_4206_vu_prepare_role1#!##!#R#!#babel_4206_vu_prepare_role1#!#master +master_babel_4206_vu_prepare_role2#!##!#R#!#babel_4206_vu_prepare_role2#!#master +master_babel_4206_vu_prepare_user1#!#babel_4206_vu_prepare_login1#!#S#!#babel_4206_vu_prepare_user1#!#master +master_babel_4206_vu_prepare_user2#!#babel_4206_vu_prepare_login2#!#S#!#babel_4206_vu_prepare_user2#!#master +~~END~~ + diff --git a/test/JDBC/expected/objectproperty-vu-cleanup.out b/test/JDBC/expected/objectproperty-vu-cleanup.out index 617364f07e..2b600a91df 100644 --- a/test/JDBC/expected/objectproperty-vu-cleanup.out +++ b/test/JDBC/expected/objectproperty-vu-cleanup.out @@ -1,3 +1,29 @@ +-- 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) = 'objectproperty_login_1' 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~~ + + +-- tsql +drop user objectproperty_login_1 +go + +drop login objectproperty_login_1 +go -- =============== OwnerId =============== -- Cleanup DROP TABLE objectproperty_vu_prepare_ownerid_schema.objectproperty_vu_prepare_ownerid_table diff --git a/test/JDBC/expected/objectproperty-vu-prepare.out b/test/JDBC/expected/objectproperty-vu-prepare.out index fac3c6d115..5cdbba3647 100644 --- a/test/JDBC/expected/objectproperty-vu-prepare.out +++ b/test/JDBC/expected/objectproperty-vu-prepare.out @@ -1,3 +1,10 @@ +-- Used to test when user does not have permission on the object +CREATE LOGIN objectproperty_login_1 WITH PASSWORD = '12345678' +go + +create user objectproperty_login_1 +go + -- =============== OwnerId =============== -- Setup CREATE SCHEMA objectproperty_vu_prepare_ownerid_schema diff --git a/test/JDBC/expected/objectproperty-vu-verify.out b/test/JDBC/expected/objectproperty-vu-verify.out index 5adb0c1275..363018b12e 100644 --- a/test/JDBC/expected/objectproperty-vu-verify.out +++ b/test/JDBC/expected/objectproperty-vu-verify.out @@ -101,6 +101,36 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +select user_name() +go +~~START~~ +nvarchar +objectproperty_login_1 +~~END~~ + + +-- user does not have permission on the object (should return NO rows as object_id returns NULL) +SELECT OBJECTPROPERTY(ct.object_id, 'isdefaultcnst') +from sys.default_constraints ct +where parent_object_id = OBJECT_ID('objectproperty_vu_prepare_isdefaultcnst_table') +GO +~~START~~ +int +~~END~~ + + +-- user does not have permission on the object (should return NO rows as object_id returns NULL) +SELECT OBJECTPROPERTY(ct.object_id, 'isdefaultcnst') +from sys.default_constraints ct +where parent_object_id = OBJECT_ID('objectproperty_vu_prepare_isdefaultcnst_table2') +GO +~~START~~ +int +~~END~~ + + +-- tsql -- =============== ExecIsQuotedIdentOn =============== -- Does not function properly due to sys.sql_modules not recording the correct settings @@ -139,6 +169,34 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_execisquotedident_proc_off'), 'ExecIsQuotedIdentOn') +GO +~~START~~ +int + +~~END~~ + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_execisquotedident_proc_on'), 'ExecIsQuotedIdentOn') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_execisquotedident_table'), 'ExecIsQuotedIdentOn') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsMSShipped =============== -- Test for object that exists but isn't ms_shipped SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_is_ms_shipped_table'), 'IsMSShipped') @@ -157,6 +215,88 @@ int 1 ~~END~~ +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.xp_qv'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.xp_instance_regread'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.sp_addlinkedserver'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.sp_addlinkedsrvlogin'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.sp_dropserver'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.sp_droplinkedsrvlogin'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.sp_testlinkedserver'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.sp_enum_oledb_providers'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + + +USE msdb +GO +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.fn_syspolicy_is_automation_enabled'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.syspolicy_configuration'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +SELECT OBJECTPROPERTY(OBJECT_ID('dbo.syspolicy_system_health_state'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + +USE master +GO -- Test for invalid object SELECT OBJECTPROPERTY(0, 'IsMSShipped') @@ -167,6 +307,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_is_ms_shipped_table'), 'IsMSShipped') +GO +~~START~~ +int + +~~END~~ + + +-- user does have permission on the object and the object is ms shipped (should return 1) +SELECT OBJECTPROPERTY(OBJECT_ID('sys.sp_tables'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + + +-- tsql -- =============== TableFullTextPopulateStatus =============== -- Test with table object SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_tablefulltextpopulatestatus_table'), 'TableFullTextPopulateStatus') @@ -195,6 +355,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_tablefulltextpopulatestatus_table'), 'TableFullTextPopulateStatus') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_tablefulltextpopulatestatus_proc'), 'TableFullTextPopulateStatus') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== TableHasVarDecimalStorageFormat =============== -- Test with table object SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_TableHasVarDecimalStorageFormat_table'), 'TableHasVarDecimalStorageFormat') @@ -223,6 +403,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_TableHasVarDecimalStorageFormat_table'), 'TableHasVarDecimalStorageFormat') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_TableHasVarDecimalStorageFormat_proc'), 'TableHasVarDecimalStorageFormat') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsSchemaBound =============== -- Currently does not work due to hardcoded value in sys.sql_modules @@ -262,6 +462,35 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsSchemaBound_function_false'), 'IsSchemaBound') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsSchemaBound_function_true'), 'IsSchemaBound') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsSchemaBound_table'), 'IsSchemaBound') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== ExecIsAnsiNullsOn =============== @@ -311,6 +540,25 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_ansi_nulls_off_proc'), 'ExecIsAnsiNullsOn') +GO +~~START~~ +int + +~~END~~ + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_ansi_nulls_on_proc'), 'ExecIsAnsiNullsOn') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsDeterministic =============== -- Currently does not work since INFORMATION_SCHEMA.ROUTINES does not evaluate if a function is deterministic @@ -350,6 +598,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsDeterministic_function_yes'), 'IsDeterministic') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsDeterministic_table'), 'IsDeterministic') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsProcedure =============== -- Test for success SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsProcedure_proc'), 'IsProcedure') @@ -378,7 +646,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsProcedure_proc'), 'IsProcedure') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsProcedure_table'), 'IsProcedure') +GO +~~START~~ +int + +~~END~~ + +-- tsql -- =============== IsTable =============== -- Test for correct case SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTable_table'), 'IsTable') @@ -407,6 +694,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTable_table'), 'IsTable') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTable_proc'), 'IsTable') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsView =============== -- Test for correct case SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsView_view'), 'IsView') @@ -435,6 +742,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsView_view'), 'IsView') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsView_table'), 'IsView') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsUserTable =============== -- Test for correct case SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsUserTable_table'), 'IsUserTable') @@ -463,6 +790,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsUserTable_table'), 'IsUserTable') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsUserTable_view'), 'IsUserTable') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsTableFunction =============== -- Test for valid table function (should return 1) SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTableFunction_tablefunction'), 'IsTableFunction') @@ -500,6 +847,35 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTableFunction_tablefunction'), 'IsTableFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTableFunction_inlinetablefunction'), 'IsTableFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTableFunction_function'), 'IsTableFunction') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsInlineFunction =============== -- Test for correct case (should return 1) SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsInlineFunction_tablefunction'), 'IsInlineFunction') @@ -528,6 +904,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsInlineFunction_tablefunction'), 'IsInlineFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsInlineFunction_function'), 'IsInlineFunction') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsScalarFunction =============== -- Test for correct case SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsScalarFunction_function'), 'IsScalarFunction') @@ -556,6 +952,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsScalarFunction_function'), 'IsScalarFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsScalarFunction_table'), 'IsScalarFunction') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsPrimaryKey =============== -- Test for correct case SELECT OBJECTPROPERTY((SELECT TOP(1) object_id FROM sys.all_objects where name like '%objectproperty_vu_prepare_pk%' ), 'IsPrimaryKey') @@ -584,6 +1000,17 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsPrimaryKey_table'), 'IsPrimaryKey') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsIndexed =============== -- Test for correct case SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsIndexed_table'), 'IsIndexed') @@ -612,6 +1039,26 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsIndexed_table'), 'IsIndexed') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsIndexed_nonindexed_table'), 'IsIndexed') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsDefault =============== -- NOTE: Defaults are currently not supported so will return 0 @@ -633,6 +1080,17 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsDefault_table'), 'IsDefault') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsRule =============== -- NOTE: Rules are currently not supported so will return 0 @@ -654,6 +1112,17 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsRule_table'), 'IsRule') +GO +~~START~~ +int + +~~END~~ + + +-- tsql -- =============== IsTrigger =============== -- Test for correct case SELECT OBJECTPROPERTY(OBJECT_ID('objectproperty_vu_prepare_IsTrigger_trigger', 'TR'), 'IsTrigger') @@ -681,3 +1150,22 @@ int ~~END~~ + +-- tsql user=objectproperty_login_1 password=12345678 +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTrigger_trigger', 'TR'), 'IsTrigger') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTrigger_table', 'TR'), 'IsTrigger') +GO +~~START~~ +int + +~~END~~ + diff --git a/test/JDBC/expected/objectproperty.out b/test/JDBC/expected/objectproperty.out index 99fb0b249a..97f771d82b 100644 --- a/test/JDBC/expected/objectproperty.out +++ b/test/JDBC/expected/objectproperty.out @@ -1,9 +1,16 @@ +-- used to test when user does not have permission on the object +CREATE LOGIN objectproperty_login_1 WITH PASSWORD = '12345678' +go + -- Global setup for tests CREATE DATABASE db1 GO USE db1 GO +create user objectproperty_login_1 +go + -- =============== OwnerId =============== -- Setup @@ -129,7 +136,46 @@ int ~~END~~ +USE master; +go + +-- tsql user=objectproperty_login_1 password=12345678 +USE db1 +GO + +select user_name() +go +~~START~~ +nvarchar +objectproperty_login_1 +~~END~~ + + +-- user does not have permission on the object (should return NO rows as object_id returns NULL) +SELECT OBJECTPROPERTY(ct.object_id, 'isdefaultcnst') +from sys.default_constraints ct +where parent_object_id = OBJECT_ID('isdefaultcnst_table') +GO +~~START~~ +int +~~END~~ + + +-- user does not have permission on the object (should return NO rows as object_id returns NULL) +SELECT OBJECTPROPERTY(ct.object_id, 'isdefaultcnst') +from sys.default_constraints ct +where parent_object_id = OBJECT_ID('isdefaultcnst_table2') +GO +~~START~~ +int +~~END~~ + + +-- tsql -- Cleanup +USE db1 +GO + DROP TABLE isdefaultcnst_table GO @@ -192,6 +238,40 @@ int ~~END~~ + +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('execisquotedident_proc_off'), 'ExecIsQuotedIdentOn') +GO +~~START~~ +int + +~~END~~ + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('execisquotedident_proc_on'), 'ExecIsQuotedIdentOn') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('execisquotedident_table'), 'ExecIsQuotedIdentOn') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go -- Cleanup DROP PROC execisquotedident_proc_on GO @@ -233,6 +313,31 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('is_ms_shipped_table'), 'IsMSShipped') +GO +~~START~~ +int + +~~END~~ + + +-- user does have permission on the object and the object is ms shipped (should return 1) +SELECT OBJECTPROPERTY(OBJECT_ID('sys.sp_tables'), 'IsMSShipped') +GO +~~START~~ +int +1 +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE is_ms_shipped_table GO @@ -275,6 +380,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('tablefulltextpopulatestatus_table'), 'TableFullTextPopulateStatus') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('tablefulltextpopulatestatus_proc'), 'TableFullTextPopulateStatus') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE tablefulltextpopulatestatus_table GO @@ -320,6 +451,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('TableHasVarDecimalStorageFormat_table'), 'TableHasVarDecimalStorageFormat') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('TableHasVarDecimalStorageFormat_proc'), 'TableHasVarDecimalStorageFormat') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE TableHasVarDecimalStorageFormat_table GO @@ -385,6 +542,41 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsSchemaBound_function_false'), 'IsSchemaBound') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsSchemaBound_function_true'), 'IsSchemaBound') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsSchemaBound_table'), 'IsSchemaBound') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsSchemaBound_table GO @@ -464,6 +656,31 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('ansi_nulls_off_proc'), 'ExecIsAnsiNullsOn') +GO +~~START~~ +int + +~~END~~ + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('ansi_nulls_on_proc'), 'ExecIsAnsiNullsOn') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP PROC ansi_nulls_off_proc GO @@ -533,6 +750,41 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsDeterministic_function_yes'), 'IsDeterministic') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsDeterministic_function_yes'), 'IsDeterministic') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsDeterministic_table'), 'IsDeterministic') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP FUNCTION IsDeterministic_function_no @@ -580,6 +832,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsProcedure_proc'), 'IsProcedure') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsProcedure_table'), 'IsProcedure') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP PROC IsProcedure_proc GO @@ -623,6 +901,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTable_table'), 'IsTable') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTable_proc'), 'IsTable') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsTable_table GO @@ -666,6 +970,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsView_view'), 'IsView') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsView_table'), 'IsView') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP VIEW IsView_view GO @@ -708,6 +1038,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsUserTable_table'), 'IsUserTable') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsUserTable_view'), 'IsUserTable') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsUserTable_table GO @@ -785,6 +1141,41 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTableFunction_tablefunction'), 'IsTableFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTableFunction_inlinetablefunction'), 'IsTableFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTableFunction_function'), 'IsTableFunction') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP FUNCTION IsTableFunction_tablefunction GO @@ -839,6 +1230,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsInlineFunction_tablefunction'), 'IsInlineFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsInlineFunction_function'), 'IsInlineFunction') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP FUNCTION IsInlineFunction_tablefunction GO @@ -886,6 +1303,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsScalarFunction_function'), 'IsScalarFunction') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsScalarFunction_table'), 'IsScalarFunction') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP FUNCTION IsScalarFunction_function GO @@ -925,6 +1368,23 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsPrimaryKey_table'), 'IsPrimaryKey') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsPrimaryKey_table GO @@ -964,6 +1424,32 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsIndexed_table'), 'IsIndexed') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsIndexed_nonindexed_table'), 'IsIndexed') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsIndexed_nonindexed_table GO @@ -996,6 +1482,23 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsDefault_table'), 'IsDefault') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsDefault_table GO @@ -1025,6 +1528,23 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsRule_table'), 'IsRule') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsRule_table GO @@ -1069,12 +1589,76 @@ int ~~END~~ +-- tsql user=objectproperty_login_1 password=12345678 +use db1 +go + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTrigger_trigger', 'TR'), 'IsTrigger') +GO +~~START~~ +int + +~~END~~ + + +-- user does not have permission on the object (should return NULL) +SELECT OBJECTPROPERTY(OBJECT_ID('IsTrigger_table', 'TR'), 'IsTrigger') +GO +~~START~~ +int + +~~END~~ + + +-- tsql +use db1 +go + -- Cleanup DROP TABLE IsTrigger_table GO + +-- logical schema is 'information_schema', we should return NULL +select objectproperty(object_id('information_schema.columns'), 'IsView') +go +use master +go +~~START~~ +int +1 +~~END~~ + + +-- 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) = 'objectproperty_login_1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +-- tsql -- Global cleanup for tests USE master GO + +drop login objectproperty_login_1 +go + DROP DATABASE db1 GO diff --git a/test/JDBC/expected/openquery-vu-cleanup.out b/test/JDBC/expected/openquery-vu-cleanup.out index 4b58134b65..7b871a1fd9 100644 --- a/test/JDBC/expected/openquery-vu-cleanup.out +++ b/test/JDBC/expected/openquery-vu-cleanup.out @@ -4,10 +4,30 @@ GO EXEC sp_dropserver 'bbf_server_unreachable', 'droplogins' GO +EXEC sp_dropserver 'bbf_server_1', 'droplogins' +GO + +EXEC sp_dropserver 'bbf_server_2', 'droplogins' +GO + -- psql DROP EXTENSION IF EXISTS tds_fdw CASCADE; GO -- tsql +-- check if all the linked servers are dropped after dropping tds_fdw +SELECT servername, query_timeout, connect_timeout FROM babelfish_server_options +GO +~~START~~ +varchar#!#int#!#int +~~END~~ + + DROP VIEW openquery_vu_prepare__openquery_view GO + +DROP PROCEDURE openquery_vu_prepare__openquery_proc +GO + +DROP FUNCTION openquery_vu_prepare__openquery_func() +GO diff --git a/test/JDBC/expected/openquery-vu-prepare.out b/test/JDBC/expected/openquery-vu-prepare.out index a78e8aea76..fc6311388e 100644 --- a/test/JDBC/expected/openquery-vu-prepare.out +++ b/test/JDBC/expected/openquery-vu-prepare.out @@ -19,6 +19,344 @@ GO EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server_unreachable', @useself = 'FALSE', @rmtuser = 'dummy_usr', @rmtpassword = 'dummy_pwd' GO +-- Create a non-existing linked server to test connect timeout +EXEC sp_addlinkedserver @server = N'bbf_server_2', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc='1.2.3.4', @catalog=N'master' +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server_2', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +-- Test sp_serveroption procedure +EXEC sp_addlinkedserver @server = N'bbf_server_1', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server_1', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +-- sp_serveroption with invalid server name. Should throw error +EXEC sp_serveroption @server='invalid_server', @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server 'invalid_server' does not exist. Use sp_linkedservers to show available servers.)~~ + + +EXEC sp_serveroption @server='invalid_server', @optname='connect timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server 'invalid_server' does not exist. Use sp_linkedservers to show available servers.)~~ + + +-- sp_serveroption with invalid server option. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='invalid option', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option provided for sp_serveroption. Only 'query timeout' and 'connect timeout' are currently supported.)~~ + + +-- sp_serveroption with server as NULL. Should throw error +EXEC sp_serveroption @server=NULL, @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @server parameter cannot be NULL)~~ + + +EXEC sp_serveroption @server=NULL, @optname='connect timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @server parameter cannot be NULL)~~ + + +-- sp_serveroption with optname as NULL. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname=NULL, @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optname parameter cannot be NULL)~~ + + +-- sp_serveroption with optvalue as NULL. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue=NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optvalue parameter cannot be NULL)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue=NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optvalue parameter cannot be NULL)~~ + + +-- sp_serveroption with negative optvalue +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='-5' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='-55' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with float optvalue. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='1.0001' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='1.0001' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with optvalue greater than INT_MAX. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='2147483648' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: query timeout value provided is out of range)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='2147483648' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: connect timeout value provided is out of range)~~ + + +-- sp_serveroption with optvalue containing characters other than 0-9. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='0abdejc' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='0abcsdejc' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with optvalue = INT_MAX +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='2147483647' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='2147483647' +GO + +-- sp_serveroption with optvalue containing leading zeroes +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='0000002' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='00000007' +GO + +-- check the value of query timeout and connect timeout from sys.servers +select name, query_timeout, connect_timeout from sys.servers where name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int#!#int +bbf_server_1#!#2#!#7 +~~END~~ + + +-- sp_serveroption with optvalue containing + at the beginning +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='+9' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='+11' +GO + +-- check the value of query timeout and connect timeout from sys.servers +select name, query_timeout, connect_timeout from sys.servers where name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int#!#int +bbf_server_1#!#9#!#11 +~~END~~ + + +-- more than one + . Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='++7' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='++6' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with optvalue empty. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- check the value of query timeout and connect timeout from sys.servers +select name, query_timeout, connect_timeout from sys.servers where name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int#!#int +bbf_server_1#!#9#!#11 +~~END~~ + + +-- sp_serveroption with optvalue '+'. +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='+' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='+' +GO + +-- check the value of query timeout and connect timeout from sys.servers +select name, query_timeout, connect_timeout from sys.servers where name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int#!#int +bbf_server_1#!#0#!#0 +~~END~~ + + +-- sp_serveroption with optvalue '+0'. +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='+0' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='+0' +GO + +-- check the value of query timeout and connect timeout from sys.servers +select name, query_timeout, connect_timeout from sys.servers where name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int#!#int +bbf_server_1#!#0#!#0 +~~END~~ + + +-- sp_serveroption with valid server, optname and optvalue +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='5' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='5' +GO + +-- optname is case insensitive +EXEC sp_serveroption @server='bbf_server_1', @optname='queRY tiMEoUt', @optvalue='1' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='coNNect TiMeouT', @optvalue='1' +GO + +-- ignore trailing spaces in all the arguments +EXEC sp_serveroption @server='bbf_server_1 ', @optname='query timeout ', @optvalue='1 ' +GO + +EXEC sp_serveroption @server='bbf_server_1 ', @optname='connect timeout ', @optvalue='1 ' +GO + +-- do not ignore leading spaces in @server argument +EXEC sp_serveroption @server=' bbf_server_1', @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server ' bbf_server_1' does not exist. Use sp_linkedservers to show available servers.)~~ + + +EXEC sp_serveroption @server=' bbf_server_1', @optname='connect timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server ' bbf_server_1' does not exist. Use sp_linkedservers to show available servers.)~~ + + +-- do not ignore leading spaces in @optname argument +EXEC sp_serveroption @server='bbf_server_1', @optname=' query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option provided for sp_serveroption. Only 'query timeout' and 'connect timeout' are currently supported.)~~ + + +EXEC sp_serveroption @server='bbf_server_2', @optname=' connect timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option provided for sp_serveroption. Only 'query timeout' and 'connect timeout' are currently supported.)~~ + + +-- ignore leading spaces in @optvalue argument +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue=' 1' +GO + +EXEC sp_serveroption @server='bbf_server_2', @optname='connect timeout', @optvalue=' 1' +GO + +-- psql +SELECT * FROM sys.babelfish_inconsistent_metadata() where schema_name='pg_catalog' AND object_name='srvname'; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#jsonb +~~END~~ + + +-- Output passed rules +SELECT * FROM sys.babelfish_inconsistent_metadata(true) where schema_name='pg_catalog' AND object_name='srvname'; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#jsonb +name#!#pg_catalog#!#srvname#!#{"Rule": " in babelfish_server_options must also exist in pg_foreign_server"} +name#!#pg_catalog#!#srvname#!#{"Rule": " in babelfish_server_options must also exist in pg_foreign_server"} +name#!#pg_catalog#!#srvname#!#{"Rule": " in babelfish_server_options must also exist in pg_foreign_server"} +name#!#pg_catalog#!#srvname#!#{"Rule": " in babelfish_server_options must also exist in pg_foreign_server"} +~~END~~ + + +-- tsql -- Create a view dependent on OPENQUERY CREATE VIEW openquery_vu_prepare__openquery_view AS SELECT * FROM OPENQUERY(bbf_server, 'SELECT 1') GO + +CREATE PROCEDURE openquery_vu_prepare__openquery_proc AS SELECT * FROM OPENQUERY(bbf_server, 'SELECT 2') +GO + +CREATE FUNCTION openquery_vu_prepare__openquery_func() +RETURNS INT +AS +BEGIN +DECLARE @i int +SELECT @i = COUNT(*) FROM OPENQUERY(bbf_server, 'SELECT 2') +RETURN @i +END +GO diff --git a/test/JDBC/expected/openquery-vu-verify.out b/test/JDBC/expected/openquery-vu-verify.out index 3daaa4ca45..e19d98d657 100644 --- a/test/JDBC/expected/openquery-vu-verify.out +++ b/test/JDBC/expected/openquery-vu-verify.out @@ -3492,3 +3492,53 @@ varchar Query having both 'single' and "double" quotes ~~END~~ + +# Test query timeout behaviour in OPENQUERY +# check the value of query timeout from sys.servers +select name, query_timeout from sys.servers where name = 'bbf_server_1' +~~START~~ +varchar#!#int +bbf_server_1#!#1 +~~END~~ + + +# execute a query which takes more time than the timeout set +SELECT * FROM OPENQUERY(bbf_server_1, 'select CAST(pg_sleep(5) AS text)') +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: DB #: 20003, DB Msg: server connection timed out, OS #: 0, OS Msg: Success, Level: 6)~~ + + +# Test connect timeout behaviour in OPENQUERY +# check the value of connect timeout from sys.servers +select name, connect_timeout from sys.servers where name = 'bbf_server_2' +~~START~~ +varchar#!#int +bbf_server_2#!#1 +~~END~~ + + +# Make openquery against a non-existing server +SELECT * FROM OPENQUERY(bbf_server_2, 'select 1') +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: DB #: 20009, DB Msg: Unable to connect: server is unavailable or does not exist (1.2.3.4), OS #: 110, OS Msg: Connection timed out, Level: 9)~~ + + +# Test procedure dependent on OPENQUERY +EXEC openquery_vu_prepare__openquery_proc +~~START~~ +int +2 +~~END~~ + + +# Test function dependent on OPENQUERY +SELECT openquery_vu_prepare__openquery_func() +~~START~~ +int +1 +~~END~~ + diff --git a/test/JDBC/expected/openquery_upgrd-vu-cleanup.out b/test/JDBC/expected/openquery_upgrd-vu-cleanup.out index e697cecc2a..7614447561 100644 --- a/test/JDBC/expected/openquery_upgrd-vu-cleanup.out +++ b/test/JDBC/expected/openquery_upgrd-vu-cleanup.out @@ -6,9 +6,23 @@ DROP EXTENSION IF EXISTS tds_fdw CASCADE; GO ~~WARNING (Code: 0)~~ -~~WARNING (Message: drop cascades to 3 other objects Server SQLState: 00000)~~ +~~WARNING (Message: drop cascades to 5 other objects Server SQLState: 00000)~~ -- tsql +-- check if all the linked servers are dropped after dropping tds_fdw +SELECT servername, query_timeout FROM babelfish_server_options +GO +~~START~~ +varchar#!#int +~~END~~ + + -- DROP VIEW openquery_vu_prepare__openquery_view GO + +DROP PROCEDURE openquery_upgrd_vu_prepare__openquery_proc +GO + +DROP FUNCTION openquery_upgrd_vu_prepare__openquery_func() +GO diff --git a/test/JDBC/expected/openquery_upgrd-vu-prepare.out b/test/JDBC/expected/openquery_upgrd-vu-prepare.out index ea2523049c..1dc8022ac2 100644 --- a/test/JDBC/expected/openquery_upgrd-vu-prepare.out +++ b/test/JDBC/expected/openquery_upgrd-vu-prepare.out @@ -12,7 +12,126 @@ GO EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' GO +-- Test sp_serveroption procedure +EXEC sp_addlinkedserver @server = N'bbf_server_1', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server_1', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +-- sp_serveroption with invalid server name. Should throw error +EXEC sp_serveroption @server='invalid_server', @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server 'invalid_server' does not exist. Use sp_linkedservers to show available servers.)~~ + + +-- sp_serveroption with invalid server option. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='invalid option', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option provided for sp_serveroption. Only 'query timeout' is currently supported.)~~ + + +-- sp_serveroption with server as NULL. Should throw error +EXEC sp_serveroption @server=NULL, @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @server parameter cannot be NULL)~~ + + +-- sp_serveroption with optname as NULL. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname=NULL, @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optname parameter cannot be NULL)~~ + + +-- sp_serveroption with optvalue as NULL. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue=NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optvalue parameter cannot be NULL)~~ + + +-- sp_serveroption with negative optvalue +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='-5' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +-- sp_serveroption with float optvalue. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='1.0001' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +-- sp_serveroption with optvalue greater than INT_MAX. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='2147483648' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Query timeout value provided is out of range)~~ + + +-- sp_serveroption with optvalue containing characters other than 0-9. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='0abdejc' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +-- sp_serveroption with optvalue = INT_MAX +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='2147483647' +GO + +-- sp_serveroption with optvalue containing leading zeroes +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='0000002' +GO + +-- optname is case insensitive +EXEC sp_serveroption @server='bbf_server_1', @optname='queRY tiMEoUt', @optvalue='5' +GO + +-- sp_serveroption with valid server, optname and optvalue +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='1' +GO + +-- check if the linked servers added above are reflected in babelfish_server_options catalog +SELECT servername, query_timeout FROM babelfish_server_options WHERE servername = 'bbf_server' OR servername = 'bbf_server_1' +GO +~~START~~ +varchar#!#int +bbf_server#!#0 +bbf_server_1#!#1 +~~END~~ + + -- Create a view dependent on OPENQUERY -- Commenting this out until we figure out a way to support CREATE VIEW with OPENQUERY in MVU -- CREATE VIEW openquery_vu_prepare__openquery_view AS SELECT * FROM OPENQUERY(bbf_server, 'SELECT 1') GO + +CREATE PROCEDURE openquery_upgrd_vu_prepare__openquery_proc AS SELECT * FROM OPENQUERY(bbf_server, 'SELECT 2') +GO + +CREATE FUNCTION openquery_upgrd_vu_prepare__openquery_func() +RETURNS INT +AS +BEGIN +DECLARE @i int +SELECT @i = COUNT(*) FROM OPENQUERY(bbf_server, 'SELECT 2') +RETURN @i +END +GO diff --git a/test/JDBC/expected/openquery_upgrd-vu-verify.out b/test/JDBC/expected/openquery_upgrd-vu-verify.out index 1e86b14deb..aa073768e2 100644 --- a/test/JDBC/expected/openquery_upgrd-vu-verify.out +++ b/test/JDBC/expected/openquery_upgrd-vu-verify.out @@ -6,5 +6,40 @@ int ~~END~~ +-- check whether query timeout value is getting persisted after the upgrade +SELECT name, query_timeout FROM sys.servers WHERE name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int +bbf_server_1#!#1 +~~END~~ + + +-- should throw error as it takes more than 5 seconds to run +SELECT * FROM OPENQUERY(bbf_server_1, 'select CAST(pg_sleep(5) AS text)') +GO +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: DB #: 20003, DB Msg: server connection timed out, OS #: 0, OS Msg: Success, Level: 6)~~ + + -- SELECT * FROM openquery_vu_prepare__openquery_view GO + +EXEC openquery_upgrd_vu_prepare__openquery_proc +GO +~~START~~ +int +2 +~~END~~ + + +SELECT openquery_upgrd_vu_prepare__openquery_func() +GO +~~START~~ +int +1 +~~END~~ + diff --git a/test/JDBC/expected/openquery_upgrd_before_15_4-vu-cleanup.out b/test/JDBC/expected/openquery_upgrd_before_15_4-vu-cleanup.out new file mode 100644 index 0000000000..7d6651b536 --- /dev/null +++ b/test/JDBC/expected/openquery_upgrd_before_15_4-vu-cleanup.out @@ -0,0 +1,28 @@ +EXEC sp_dropserver 'bbf_server', 'droplogins' +GO + +-- psql +DROP EXTENSION IF EXISTS tds_fdw CASCADE; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: drop cascades to 7 other objects Server SQLState: 00000)~~ + + +-- tsql +-- check if all the linked servers are dropped after dropping tds_fdw +SELECT servername, query_timeout, connect_timeout FROM babelfish_server_options +GO +~~START~~ +varchar#!#int#!#int +~~END~~ + + +-- DROP VIEW openquery_vu_prepare__openquery_view +GO + +DROP PROCEDURE openquery_upgrd_vu_prepare__openquery_proc +GO + +DROP FUNCTION openquery_upgrd_vu_prepare__openquery_func() +GO diff --git a/test/JDBC/expected/openquery_upgrd_before_15_4-vu-prepare.out b/test/JDBC/expected/openquery_upgrd_before_15_4-vu-prepare.out new file mode 100644 index 0000000000..0072a98b73 --- /dev/null +++ b/test/JDBC/expected/openquery_upgrd_before_15_4-vu-prepare.out @@ -0,0 +1,206 @@ +-- psql +SET client_min_messages = 'error'; +CREATE EXTENSION IF NOT EXISTS tds_fdw; +GO + +-- tsql +-- Add localhost as linked server +EXEC sp_addlinkedserver @server = N'bbf_server', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +-- Create a non-existing linked server to test connect timeout +EXEC sp_addlinkedserver @server = N'bbf_server_2', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc='1.2.3.4', @catalog=N'master' +GO + +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server_2', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +-- Test sp_serveroption procedure +EXEC sp_addlinkedserver @server = N'bbf_server_1', @srvproduct=N'', @provider=N'SQLNCLI', @datasrc=N'localhost', @catalog=N'master' +GO + +-- Add jdbc_user as linked server login +EXEC sp_addlinkedsrvlogin @rmtsrvname = 'bbf_server_1', @useself = 'FALSE', @rmtuser = 'jdbc_user', @rmtpassword = '12345678' +GO + +-- sp_serveroption with invalid server name. Should throw error +EXEC sp_serveroption @server='invalid_server', @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server 'invalid_server' does not exist. Use sp_linkedservers to show available servers.)~~ + + +EXEC sp_serveroption @server='invalid_server', @optname='connect timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The server 'invalid_server' does not exist. Use sp_linkedservers to show available servers.)~~ + + +-- sp_serveroption with invalid server option. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='invalid option', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option provided for sp_serveroption. Only 'query timeout' and 'connect timeout' are currently supported.)~~ + + +-- sp_serveroption with server as NULL. Should throw error +EXEC sp_serveroption @server=NULL, @optname='query timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @server parameter cannot be NULL)~~ + + +EXEC sp_serveroption @server=NULL, @optname='connect timeout', @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @server parameter cannot be NULL)~~ + + +-- sp_serveroption with optname as NULL. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname=NULL, @optvalue='1' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optname parameter cannot be NULL)~~ + + +-- sp_serveroption with optvalue as NULL. Should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue=NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optvalue parameter cannot be NULL)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue=NULL +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: @optvalue parameter cannot be NULL)~~ + + +-- sp_serveroption with negative optvalue +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='-5' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='-5' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with float optvalue. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='1.0001' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='1.0001' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with optvalue greater than INT_MAX. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='2147483648' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: query timeout value provided is out of range)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='2147483648' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: connect timeout value provided is out of range)~~ + + +-- sp_serveroption with optvalue containing characters other than 0-9. should throw error +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='0abdejc' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for query timeout)~~ + + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='0abdejc' +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid option value for connect timeout)~~ + + +-- sp_serveroption with optvalue = INT_MAX +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='2147483647' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='2147483647' +GO + +-- sp_serveroption with optvalue containing leading zeroes +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='0000002' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='connect timeout', @optvalue='0000002' +GO + +-- optname is case insensitive +EXEC sp_serveroption @server='bbf_server_1', @optname='queRY tiMEoUt', @optvalue='5' +GO + +EXEC sp_serveroption @server='bbf_server_1', @optname='conNeCt tiMEoUt', @optvalue='5' +GO + +-- sp_serveroption with valid server, optname and optvalue +EXEC sp_serveroption @server='bbf_server_1', @optname='query timeout', @optvalue='1' +GO + +EXEC sp_serveroption @server='bbf_server_2', @optname='connect timeout', @optvalue='1' +GO + +-- check if the linked servers added above are reflected in babelfish_server_options catalog +SELECT servername, query_timeout, connect_timeout FROM babelfish_server_options WHERE servername = 'bbf_server' OR servername = 'bbf_server_1' OR servername = 'bbf_server_2' order by servername +GO +~~START~~ +varchar#!#int#!#int +bbf_server#!#0#!#0 +bbf_server_1#!#1#!#5 +bbf_server_2#!#0#!#1 +~~END~~ + + +-- Create a view dependent on OPENQUERY +-- Commenting this out until we figure out a way to support CREATE VIEW with OPENQUERY in MVU +-- CREATE VIEW openquery_vu_prepare__openquery_view AS SELECT * FROM OPENQUERY(bbf_server, 'SELECT 1') +GO + +CREATE PROCEDURE openquery_upgrd_vu_prepare__openquery_proc AS SELECT * FROM OPENQUERY(bbf_server, 'SELECT 2') +GO + +CREATE FUNCTION openquery_upgrd_vu_prepare__openquery_func() +RETURNS INT +AS +BEGIN +DECLARE @i int +SELECT @i = COUNT(*) FROM OPENQUERY(bbf_server, 'SELECT 2') +RETURN @i +END +GO diff --git a/test/JDBC/expected/openquery_upgrd_before_15_4-vu-verify.out b/test/JDBC/expected/openquery_upgrd_before_15_4-vu-verify.out new file mode 100644 index 0000000000..88b17640fe --- /dev/null +++ b/test/JDBC/expected/openquery_upgrd_before_15_4-vu-verify.out @@ -0,0 +1,62 @@ +SELECT * FROM OPENQUERY(bbf_server, 'SELECT 123') +GO +~~START~~ +int +123 +~~END~~ + + +-- check whether query timeout value is getting persisted after the upgrade +SELECT name, query_timeout FROM sys.servers WHERE name = 'bbf_server_1' +GO +~~START~~ +varchar#!#int +bbf_server_1#!#1 +~~END~~ + + +-- should throw error as it takes more than 5 seconds to run +SELECT * FROM OPENQUERY(bbf_server_1, 'select CAST(pg_sleep(5) AS text)') +GO +~~START~~ +text +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: DB #: 20003, DB Msg: server connection timed out, OS #: 0, OS Msg: Success, Level: 6)~~ + + +-- check whether connect_timeout value is getting persisted after the upgrade +SELECT name, connect_timeout FROM sys.servers WHERE name = 'bbf_server_2' +GO +~~START~~ +varchar#!#int +bbf_server_2#!#1 +~~END~~ + + +-- should throw connection timeout error in one second as the server does not exist +SELECT * FROM OPENQUERY(bbf_server_2, 'select 1') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: TDS client library error: DB #: 20009, DB Msg: Unable to connect: server is unavailable or does not exist (1.2.3.4), OS #: 110, OS Msg: Connection timed out, Level: 9)~~ + + +-- SELECT * FROM openquery_vu_prepare__openquery_view +GO + +EXEC openquery_upgrd_vu_prepare__openquery_proc +GO +~~START~~ +int +2 +~~END~~ + + +SELECT openquery_upgrd_vu_prepare__openquery_func() +GO +~~START~~ +int +1 +~~END~~ + 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/expected/ownership_restrictions_from_pg.out b/test/JDBC/expected/ownership_restrictions_from_pg.out index 393440515c..e8da177989 100644 --- a/test/JDBC/expected/ownership_restrictions_from_pg.out +++ b/test/JDBC/expected/ownership_restrictions_from_pg.out @@ -1,94 +1,847 @@ -- 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; -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 --- psql user=ownership_restrictions_from_pg_test_user password=12345678 +-- psql user=ownership_restrictions_from_pg_login1 password=12345678 +-- If tsql login connected through psql Alter ROLE of an bbf created logins for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations and all alter role operations for bbf created users/roles +-- 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)~~ --- psql --- Dropping login from psql port should fail -DROP ROLE ownership_restrictions_from_pg_login1; +ALTER ROLE master_ownership_restrictions_from_pg_role1 VALID UNTIL 'infinity'; GO ~~ERROR (Code: 0)~~ -~~ERROR (Message: ERROR: Babelfish-created login cannot be dropped or altered outside of a Babelfish session - Server SQLState: 55006)~~ +~~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 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)~~ --- Create a non babelfish role that is a member of master_guest --- and enable dropping -CREATE ROLE ownership_restrictions_from_pg_role2 IN ROLE master_guest, tempdb_guest, msdb_guest; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with ENCRYPTED password '12345678'; GO +~~ERROR (Code: 0)~~ -DROP ROLE ownership_restrictions_from_pg_role2; +~~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 password '12345678'; GO ~~ERROR (Code: 0)~~ -~~ERROR (Message: ERROR: Babelfish-created login cannot be dropped or altered outside of a Babelfish session - Server SQLState: 55006)~~ +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ -SET enable_drop_babelfish_role = true; +ALTER ROLE master_ownership_restrictions_from_pg_role1 with password NULL; GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + -DROP ROLE ownership_restrictions_from_pg_role2; +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)~~ + -SET enable_drop_babelfish_role = false; +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)~~ -CREATE ROLE ownership_restrictions_from_pg_role3; +ALTER ROLE master_ownership_restrictions_from_pg_role1 NOCREATEDB; GO +~~ERROR (Code: 0)~~ -GRANT master_guest TO ownership_restrictions_from_pg_role3; -GRANT tempdb_guest TO ownership_restrictions_from_pg_role3; -GRANT msdb_guest TO ownership_restrictions_from_pg_role3; +~~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)~~ -DROP ROLE ownership_restrictions_from_pg_role3; +~~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 login cannot be dropped or altered outside of a Babelfish session - Server SQLState: 55006)~~ +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ -SET enable_drop_babelfish_role = true; +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)~~ + -DROP ROLE ownership_restrictions_from_pg_role3; +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)~~ + -SET enable_drop_babelfish_role = false; +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)~~ + --- Test a regular role -CREATE ROLE ownership_restrictions_from_pg_role4; +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)~~ + -DROP ROLE ownership_restrictions_from_pg_role4; +ALTER ROLE master_ownership_restrictions_from_pg_role1 INHERIT; GO +~~ERROR (Code: 0)~~ -DROP USER ownership_restrictions_from_pg_test_user; +~~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)~~ --- tsql -DROP ROLE ownership_restrictions_from_pg_role1; +~~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: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + 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 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 ownership_restrictions_from_pg_login1 VALID UNTIL 'infinity'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 with ENCRYPTED password '12345678'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 with password NULL; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 with password '12345678'; +GO + +ALTER ROLE ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 NOBYPASSRLS; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- after connection limit set to 1, shouldn't be able to connect to multiple sessions +ALTER ROLE ownership_restrictions_from_pg_login1 WITH CONNECTION LIMIT 1; +GO + +-- tsql user=ownership_restrictions_from_pg_login1 password=12345678 +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: too many connections for role "ownership_restrictions_from_pg_login1" )~~ + + +-- psql user=ownership_restrictions_from_pg_login1 password=12345678 +ALTER ROLE ownership_restrictions_from_pg_login1 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 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)~~ + + +-- 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 '12345678'; +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 '12345678'; +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 for password, +-- connection limit and valid until should be working fine +-- and the rest of alter role operations and all alter role operations for bbf created users/roles +-- 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 +~~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 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 '12345678'; +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 password '12345678'; +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 password NULL; +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 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: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + 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 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 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 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 ownership_restrictions_from_pg_login1 with ENCRYPTED password '12345678'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 with password NULL; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 with password '12345678'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 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 ownership_restrictions_from_pg_login1 WITH CONNECTION LIMIT 1; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied + Server SQLState: 42501)~~ + + +ALTER ROLE ownership_restrictions_from_pg_login1 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 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)~~ + + +-- 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 '12345678'; +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 '12345678'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created logins/users/roles cannot be altered outside of a Babelfish session + Server SQLState: 42501)~~ + + +-- psql +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 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/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..efca534e76 --- /dev/null +++ b/test/JDBC/expected/ownership_restrictions_from_pg_su_user.out @@ -0,0 +1,220 @@ +-- tsql +-- This test file checks the changes which are ignored in the tod run +-- As tod will not be able to create an SUPERUSER +-- and testing on jdbc_testdb(where bbf is initialized) is not possible +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 +-- Dropping login from psql port should fail for superuser +DROP ROLE ownership_restrictions_from_pg_login1; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created login cannot be dropped or altered outside of a Babelfish session + Server SQLState: 55006)~~ + + +-- Create a non babelfish role that is a member of master_guest +-- and enable dropping +CREATE ROLE ownership_restrictions_from_pg_role2 IN ROLE master_guest, tempdb_guest, msdb_guest; +GO + +DROP ROLE ownership_restrictions_from_pg_role2; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created login cannot be dropped or altered outside of a Babelfish session + Server SQLState: 55006)~~ + + +SET enable_drop_babelfish_role = true; +GO + +DROP ROLE ownership_restrictions_from_pg_role2; +GO + +SET enable_drop_babelfish_role = false; +GO + +CREATE ROLE ownership_restrictions_from_pg_role3; +GO + +GRANT master_guest TO ownership_restrictions_from_pg_role3; +GRANT tempdb_guest TO ownership_restrictions_from_pg_role3; +GRANT msdb_guest TO ownership_restrictions_from_pg_role3; +GO + +DROP ROLE ownership_restrictions_from_pg_role3; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: Babelfish-created login cannot be dropped or altered outside of a Babelfish session + Server SQLState: 55006)~~ + + +SET enable_drop_babelfish_role = true; +GO + +DROP ROLE ownership_restrictions_from_pg_role3; +GO + +SET enable_drop_babelfish_role = false; +GO + +-- Test a regular role +CREATE ROLE ownership_restrictions_from_pg_role4; +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 + +-- 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/expected/parallel_query/BABEL-3291.out b/test/JDBC/expected/parallel_query/BABEL-3291.out new file mode 100644 index 0000000000..8d8a690fe2 --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-3291.out @@ -0,0 +1,66 @@ +drop table if exists babel_3291_t1 +go + +create table babel_3291_t1(a1 int PRIMARY KEY, b1 int) +go + +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.enable_pg_hint', 'on', false); +go +~~START~~ +text +on +~~END~~ + + +set babelfish_showplan_all on +go + +/* + * Run a SELECT query without any hints to ensure that un-hinted queries still work. + * This also ensures that when the SELECT query is not hinted it produces a different plan(index scan) + * than the sequential scan that we're hinting in the query below. This verifies that the next test is actually valid. + * If the planner was going to choose a sequential scan anyway, the next test wouldn't actually prove that hints were working. + */ +select * from babel_3291_t1 where a1 = 1 +go +~~START~~ +text +Query Text: select * from babel_3291_t1 where a1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using babel_3291_t1_pkey on babel_3291_t1 + Index Cond: (a1 = 1) +~~END~~ + + +/* + * Run a SELECT query and give the hint to follow a sequential scan. + * The query plan should now use a sequential scan instead of the index scan it uses in the un-hinted test above. + */ +select /*+SeqScan(babel_3291_t1)*/ * from babel_3291_t1 where a1 = 1 +go +~~START~~ +text +Query Text: select /*+SeqScan(babel_3291_t1)*/ * from babel_3291_t1 where a1 = 1 +Gather + Workers Planned: 3 + -> Parallel Seq Scan on babel_3291_t1 + Filter: (a1 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- cleanup +drop table babel_3291_t1 +go diff --git a/test/JDBC/expected/parallel_query/BABEL-3292.out b/test/JDBC/expected/parallel_query/BABEL-3292.out new file mode 100644 index 0000000000..bc4da8b077 --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-3292.out @@ -0,0 +1,974 @@ +drop table if exists babel_3292_t1 +go + +drop table if exists babel_3292_t2 +go + +create table babel_3292_t1(a1 int PRIMARY KEY, b1 int, c1 int) +go + +create index index_babel_3292_t1_b1 on babel_3292_t1(b1) +go + +create index inDex_BABEL_3292_T1_c1 on babel_3292_t1(c1) +go + +create table babel_3292_t2(a2 int PRIMARY KEY, b2 int, c2 int) +go + +create index index_babel_3292_t2_b2 on babel_3292_t2(b2) +go + +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.enable_pg_hint', 'on', false); +go +~~START~~ +text +on +~~END~~ + + +set babelfish_showplan_all on +go + +-- Test SELECT queries with and without hints +/* + * Run a SELECT query without any hints to ensure that un-hinted queries still work. + * This also ensures that when the SELECT query is not hinted it produces a different plan(bitmap heap scan and bitmap index scan) + * than the index scan that we're hinting in the queries below. This verifies that the next set of tests are actually valid. + * If the planner was going to choose a index scan anyway, the next test wouldn't actually prove that hints were working. + */ +select * from babel_3292_t1 where b1 = 1 +go +~~START~~ +text +Query Text: select * from babel_3292_t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +/* + * Run SELECT queries and give the hint to follow a index scan using different syntaxes. + * The query plan should now use a idex scan instead of the bitmap heap and bitmap index scan it uses in the un-hinted test above. + */ +select * from babel_3292_t1 (index(index_babel_3292_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 (index=index_babel_3292_t1_b1) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 with(index(index_babel_3292_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 with(index=index_babel_3292_t1_b1) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 t1 with(index=index_babel_3292_t1_b1) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 as t1 with(index=index_babel_3292_t1_b1) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 as t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 where b1=1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 where b1=1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 t1 where b1=1 option(table hint(t1, index(index_babel_3292_t1_b1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 t1 where b1=1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 t1 + Index Cond: (b1 = 1) +~~END~~ + + +-- Test with multiple index hints +select * from babel_3292_t1 where b1 = 1 and c1 = 1 +go +~~START~~ +text +Query Text: select * from babel_3292_t1 where b1 = 1 and c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: ((c1 = 1) AND (b1 = 1)) + -> BitmapAnd + -> Bitmap Index Scan on index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c + Index Cond: (c1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 with(index(index_babel_3292_t1_b1), index(index_babel_3292_t1_c1)) where b1 = 1 and c1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t1 index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c) */ * from babel_3292_t1 where b1 = 1 and c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c on babel_3292_t1 + Index Cond: (c1 = 1) + Filter: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 where b1 = 1 and c1 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1), index(index_babel_3292_t1_c1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t1 index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c) */ * from babel_3292_t1 where b1 = 1 and c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c on babel_3292_t1 + Index Cond: (c1 = 1) + Filter: (b1 = 1) +~~END~~ + + +select * from BABEL_3292_t1 where b1 = 1 and c1 = 1 option(table hint(Babel_3292_t1, index(IndeX_BABEL_3292_t1_b1), index(Index_baBel_3292_t1_C1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t1 index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c) */ * from BABEL_3292_t1 where b1 = 1 and c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c on babel_3292_t1 + Index Cond: (c1 = 1) + Filter: (b1 = 1) +~~END~~ + + +-- Test with multiple tables +select * from babel_3292_t1, babel_3292_t2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select * from babel_3292_t1, babel_3292_t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3292_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 with(index(index_babel_3292_t1_b1)), babel_3292_t2 with(index(index_babel_3292_t2_b2)) where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 , babel_3292_t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 with(index=index_babel_3292_t1_b1), babel_3292_t2 with(index=index_babel_3292_t2_b2) where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 , babel_3292_t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1, babel_3292_t2 where b1 = 1 and b2 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1)), table hint(babel_3292_t2, index(index_babel_3292_t2_b2))) +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1, babel_3292_t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 t1 with(index=index_babel_3292_t1_b1), babel_3292_t2 t2 with(index=index_babel_3292_t2_b2) where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 t1 , babel_3292_t2 t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 t1, babel_3292_t2 t2 where b1 = 1 and b2 = 1 option(table hint(t1, index(index_babel_3292_t1_b1)), table hint(t2, index(index_babel_3292_t2_b2))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 t1, babel_3292_t2 t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 t2 + Index Cond: (b2 = 1) +~~END~~ + + +-- Test INSERT queries with and without hints +insert into babel_3292_t2 select * from babel_3292_t1 where b1 = 1 +go +~~START~~ +text +Query Text: insert into babel_3292_t2 select * from babel_3292_t1 where b1 = 1 +Insert on babel_3292_t2 + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +insert into babel_3292_t2 select * from babel_3292_t1 with(index(index_babel_3292_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: insert/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ into babel_3292_t2 select * from babel_3292_t1 where b1 = 1 +Insert on babel_3292_t2 + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +insert into babel_3292_t2 select * from babel_3292_t1 where b1 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1))) +go +~~START~~ +text +Query Text: insert/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ into babel_3292_t2 select * from babel_3292_t1 where b1 = 1 +Insert on babel_3292_t2 + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +-- Test UPDATE queries with and without hints +update babel_3292_t1 set a1 = 1 where b1 = 1 +go +~~START~~ +text +Query Text: update babel_3292_t1 set a1 = 1 where b1 = 1 +Update on babel_3292_t1 + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +update babel_3292_t1 with(index(index_babel_3292_t1_b1)) set a1 = 1 where b1 = 1 +go +~~START~~ +text +Query Text: update/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ babel_3292_t1 set a1 = 1 where b1 = 1 +Update on babel_3292_t1 + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +update babel_3292_t1 set a1 = 1 where b1 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1))) +go +~~START~~ +text +Query Text: update/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ babel_3292_t1 set a1 = 1 where b1 = 1 +Update on babel_3292_t1 + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +-- Test DELETE queries with and without hints +delete from babel_3292_t1 where b1 = 1 +go +~~START~~ +text +Query Text: delete from babel_3292_t1 where b1 = 1 +Delete on babel_3292_t1 + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +delete from babel_3292_t1 with(index(index_babel_3292_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: delete/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ from babel_3292_t1 where b1 = 1 +Delete on babel_3292_t1 + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +delete from babel_3292_t1 where b1 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1))) +go +~~START~~ +text +Query Text: delete/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ from babel_3292_t1 where b1 = 1 +Delete on babel_3292_t1 + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +-- Test UNION queries with and without hints +select * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 -- None of the queries have a hint +go +~~START~~ +text +Query Text: select * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: babel_3292_t1.a1, babel_3292_t1.b1, babel_3292_t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) + -> Parallel Bitmap Heap Scan on babel_3292_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 with(index=index_babel_3292_t2_b2) where b2 = 1 -- Only one query has a hint +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: babel_3292_t1.a1, babel_3292_t1.b1, babel_3292_t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1))) -- Only one query has a hint +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: babel_3292_t2.a2, babel_3292_t2.b2, babel_3292_t2.c2 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Bitmap Heap Scan on babel_3292_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 + Index Cond: (b2 = 1) + -> Parallel Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from babel_3292_t1 with(index=index_babel_3292_t1_b1) where b1 = 1 UNION select * from babel_3292_t2 with(index=index_babel_3292_t2_b2) where b2 = 1 -- Both queries have a hint +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: babel_3292_t1.a1, babel_3292_t1.b1, babel_3292_t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1)), table hint(babel_3292_t2, index(index_babel_3292_t2_b2))) -- Both queries have a hint +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from babel_3292_t1 where b1 = 1 UNION select * from babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: babel_3292_t1.a1, babel_3292_t1.b1, babel_3292_t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +-- Test CTE queries with and without hints +with babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +go +~~START~~ +text +Query Text: with babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: ((c1 = 1) AND (b1 = 1)) + -> BitmapAnd + -> Bitmap Index Scan on index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c + Index Cond: (c1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +with babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 with(index=index_babel_3292_t1_b1) where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +go +~~START~~ +text +Query Text: with/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + Filter: (c1 = 1) +~~END~~ + + +with babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 option(table hint(babel_3292_t1, index(index_babel_3292_t1_b1))) +go +~~START~~ +text +Query Text: with/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + Filter: (c1 = 1) +~~END~~ + + +with BaBeL_3292_T1_CTE (a1, b1, c1) as (select * from BABEL_3292_t1 with(index=INDEX_BABEL_3292_T1_B1) where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +go +~~START~~ +text +Query Text: with/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) */ BaBeL_3292_T1_CTE (a1, b1, c1) as (select * from BABEL_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + Filter: (c1 = 1) +~~END~~ + + +-- Limitation: Hint given on a CTE is not applied +with babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte with(index=index_babel_3292_t1_c1) where c1 = 1 +go +~~START~~ +text +Query Text: with/*+ indexscan(babel_3292_t1_cte index_babel_3292_t1_c1babel_32961b5cc4ed008f5c7776c7f58f0abe80b) */ babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Bitmap Heap Scan on babel_3292_t1 + Recheck Cond: ((c1 = 1) AND (b1 = 1)) + -> BitmapAnd + -> Bitmap Index Scan on index_babel_3292_t1_c1babel_329c7d18660bd3d9742036705bdc0da925c + Index Cond: (c1 = 1) + -> Bitmap Index Scan on index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 + Index Cond: (b1 = 1) +~~END~~ + + +-- Only the hint given on an existing table will be applied +with babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 with(index=index_babel_3292_t1_b1) where b1 = 1) select * from babel_3292_t1_cte with(index=index_babel_3292_t1_c1) where c1 = 1 +go +~~START~~ +text +Query Text: with/*+ indexscan(babel_3292_t1 index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736) indexscan(babel_3292_t1_cte index_babel_3292_t1_c1babel_32961b5cc4ed008f5c7776c7f58f0abe80b) */ babel_3292_t1_cte (a1, b1, c1) as (select * from babel_3292_t1 where b1 = 1) select * from babel_3292_t1_cte where c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_t1_b1babel_329eaeb7a8893929b580f3d762dc8499736 on babel_3292_t1 + Index Cond: (b1 = 1) + Filter: (c1 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- cleanup +drop table babel_3292_t1 +go + +drop table babel_3292_t2 +go + + +-- Test all queries by specifying a database and schema name +use tempdb +go + +drop table if exists babel_3292_schema.t1 +go + +drop table if exists babel_3292_t2 +go + +drop schema if exists babel_3292_schema +go + +create schema babel_3292_schema +go + +create table babel_3292_schema.t1(a1 int PRIMARY KEY, b1 int, c1 int) +go + +create index index_babel_3292_schema_t1_b1 on babel_3292_schema.t1(b1) +go + +create index index_babel_3292_schema_t1_c1 on babel_3292_schema.t1(c1) +go + +create table babel_3292_t2(a2 int PRIMARY KEY, b2 int, c2 int) +go + +create index index_babel_3292_t2_b2 on babel_3292_t2(b2) +go + +set babelfish_showplan_all on +go + +select * from tempdb.babel_3292_schema.t1 (index(index_babel_3292_schema_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ * from tempdb.babel_3292_schema.t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 t1 (index(index_babel_3292_schema_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ * from tempdb.babel_3292_schema.t1 t1 where b1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 where b1=1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ * from tempdb.babel_3292_schema.t1 where b1=1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 t1 where b1=1 option(table hint(t1, index(index_babel_3292_schema_t1_b1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ * from tempdb.babel_3292_schema.t1 t1 where b1=1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 with(index(index_babel_3292_schema_t1_b1), index(index_babel_3292_schema_t1_c1)) where b1 = 1 and c1 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(t1 index_babel_3292_schema_t1_c1t1185ec046d5c38219c998001d0ae030d0) */ * from tempdb.babel_3292_schema.t1 where b1 = 1 and c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_schema_t1_c1t1185ec046d5c38219c998001d0ae030d0 on t1 + Index Cond: (c1 = 1) + Filter: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 where b1 = 1 and c1 = 1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1), index(index_babel_3292_schema_t1_c1))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(t1 index_babel_3292_schema_t1_c1t1185ec046d5c38219c998001d0ae030d0) */ * from tempdb.babel_3292_schema.t1 where b1 = 1 and c1 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3292_schema_t1_c1t1185ec046d5c38219c998001d0ae030d0 on t1 + Index Cond: (c1 = 1) + Filter: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 with(index(index_babel_3292_schema_t1_b1)), tempdb.dbo.babel_3292_t2 with(index(index_babel_3292_t2_b2)) where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 , tempdb.dbo.babel_3292_t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 t1 with(index(index_babel_3292_schema_t1_b1)), tempdb.dbo.babel_3292_t2 t2 with(index(index_babel_3292_t2_b2)) where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 t1 , tempdb.dbo.babel_3292_t2 t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1, tempdb.dbo.babel_3292_t2 where b1 = 1 and b2 = 1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1)), table hint(tempdb.dbo.babel_3292_t2, index(index_babel_3292_t2_b2))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1, tempdb.dbo.babel_3292_t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 t1, tempdb.dbo.babel_3292_t2 t2 where b1 = 1 and b2 = 1 option(table hint(t1, index(index_babel_3292_schema_t1_b1)), table hint(t2, index(index_babel_3292_t2_b2))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 t1, tempdb.dbo.babel_3292_t2 t2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 t2 + Index Cond: (b2 = 1) +~~END~~ + + +insert into tempdb.dbo.babel_3292_t2 select * from tempdb.babel_3292_schema.t1 with(index(index_babel_3292_schema_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: insert/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ into tempdb.dbo.babel_3292_t2 select * from tempdb.babel_3292_schema.t1 where b1 = 1 +Insert on babel_3292_t2 + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +insert into tempdb.dbo.babel_3292_t2 select * from tempdb.babel_3292_schema.t1 where b1 = 1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1))) +go +~~START~~ +text +Query Text: insert/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ into tempdb.dbo.babel_3292_t2 select * from tempdb.babel_3292_schema.t1 where b1 = 1 +Insert on babel_3292_t2 + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +update tempdb.babel_3292_schema.t1 with(index(index_babel_3292_schema_t1_b1)) set a1 = 1 where b1 = 1 +go +~~START~~ +text +Query Text: update/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ tempdb.babel_3292_schema.t1 set a1 = 1 where b1 = 1 +Update on t1 + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +update tempdb.babel_3292_schema.t1 set a1 = 1 where b1 = 1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1))) +go +~~START~~ +text +Query Text: update/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ tempdb.babel_3292_schema.t1 set a1 = 1 where b1 = 1 +Update on t1 + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +delete from tempdb.babel_3292_schema.t1 with(index(index_babel_3292_schema_t1_b1)) where b1 = 1 +go +~~START~~ +text +Query Text: delete/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ from tempdb.babel_3292_schema.t1 where b1 = 1 +Delete on t1 + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +delete from tempdb.babel_3292_schema.t1 where b1 = 1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1))) +go +~~START~~ +text +Query Text: delete/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) */ from tempdb.babel_3292_schema.t1 where b1 = 1 +Delete on t1 + -> Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 with(index=index_babel_3292_schema_t1_b1) where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 with(index=index_babel_3292_t2_b2) where b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: t1.a1, t1.b1, t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 t1 with(index=index_babel_3292_schema_t1_b1) where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 t2 with(index=index_babel_3292_t2_b2) where b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 t1 where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 t2 where b2 = 1 +HashAggregate + Group Key: t1.a1, t1.b1, t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 where b2 = 1 option(table hint(tempdb.babel_3292_schema.t1, index(index_babel_3292_schema_t1_b1)), table hint(tempdb.dbo.babel_3292_t2, index(index_babel_3292_t2_b2))) -- Both queries have a hint +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(babel_3292_t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 where b2 = 1 +HashAggregate + Group Key: t1.a1, t1.b1, t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3292_schema.t1 t1 where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 t2 where b2 = 1 option(table hint(t1, index(index_babel_3292_schema_t1_b1)), table hint(t2, index(index_babel_3292_t2_b2))) -- Both queries have a hint +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297) indexscan(t2 index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434) */ * from tempdb.babel_3292_schema.t1 t1 where b1 = 1 UNION select * from tempdb.dbo.babel_3292_t2 t2 where b2 = 1 +HashAggregate + Group Key: t1.a1, t1.b1, t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3292_schema_t1_b1t15233a6e220046e22743bc3bf322e4297 on t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3292_t2_b2babel_3297b13d7f53f3b499d8db9cc07605bd434 on babel_3292_t2 t2 + Index Cond: (b2 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- cleanup +drop table babel_3292_schema.t1 +go + +drop table babel_3292_t2 +go + +drop schema babel_3292_schema +go diff --git a/test/JDBC/expected/parallel_query/BABEL-3293.out b/test/JDBC/expected/parallel_query/BABEL-3293.out new file mode 100644 index 0000000000..195c20684a --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-3293.out @@ -0,0 +1,1132 @@ +drop table if exists babel_3293_t1 +go + +drop table if exists babel_3293_t2 +go + +drop table if exists babel_3293_t3 +go + +create table babel_3293_t1(a1 int PRIMARY KEY, b1 int) +go + +create index index_babel_3293_t1_b1 on babel_3293_t1(b1) +go + +create table babel_3293_t2(a2 int PRIMARY KEY, b2 int) +go + +create index index_babel_3293_t2_b2 on babel_3293_t2(b2) +go + +create table babel_3293_t3(a3 int PRIMARY KEY, b3 int) +go + +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.enable_pg_hint', 'on', false); +go +~~START~~ +text +on +~~END~~ + + +set babelfish_showplan_all on +go + +/* + * Run a SELECT query joining two tables without any join hints to ensure that un-hinted queries still work. + * This also ensures that when the SELECT query is not hinted it produces a different plan(hash join) + * than the other join plans that we're hinting in the queries below. This verifies that the next set of tests are actually valid. + */ +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Hash + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +/* + * Give the hints in the queries to follow a specified join plan. + * The query plan should now use the specified join plan instead of hash join it uses in the un-hinted test above. + */ +select * from babel_3293_t1 inner merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 t1 inner merge join babel_3293_t2 t2 on t1.a1 = t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(t1 t2) leading(t1 t2)*/ * from babel_3293_t1 t1 inner join babel_3293_t2 t2 on t1.a1 = t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (t1.a1 = t2.a2) + -> Sort + Sort Key: t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 left outer loop join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ nestloop(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 left outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from BABEL_3293_t1 LeFt ouTer LOOP join Babel_3293_T2 on BABEL_3293_t1.a1 = BABEL_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ nestloop(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from BABEL_3293_t1 LeFt ouTer join Babel_3293_T2 on BABEL_3293_t1.a1 = BABEL_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 with(index(index_babel_3293_t1_b1)) join babel_3293_t2 (index(index_babel_3293_t2_b2)) on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 -- Join query with just table hints +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3293_t1 index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210) indexscan(babel_3293_t2 index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 + Index Cond: (b1 = 1) + -> Hash + -> Index Scan using index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e on babel_3293_t2 + Index Cond: (b2 = 1) +~~END~~ + + +-- Queries with multiple joins +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t3.a3) + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Hash + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 + Index Cond: (a3 = babel_3293_t2.a2) + Filter: (b3 = 1) +~~END~~ + + +select * from babel_3293_t1 left outer merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t1.a1 = babel_3293_t3.a3 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 left outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t1.a1 = babel_3293_t3.a3 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Merge Left Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Index Scan using babel_3293_t1_pkey on babel_3293_t1 + -> Index Scan using babel_3293_t2_pkey on babel_3293_t2 + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 + Index Cond: (a3 = babel_3293_t1.a1) +~~END~~ + + +select * from babel_3293_t1 left outer merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 left outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 + Index Cond: (a3 = babel_3293_t1.a1) + Filter: (b3 = 1) +~~END~~ + + +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner merge join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2 babel_3293_t3) leading(babel_3293_t1 babel_3293_t2 babel_3293_t3)*/ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 3 + -> Merge Join + Merge Cond: (babel_3293_t3.a3 = babel_3293_t1.a1) + -> Sort + Sort Key: babel_3293_t3.a3 + -> Parallel Seq Scan on babel_3293_t3 + Filter: (b3 = 1) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Hash + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 left outer loop join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner loop join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select/*+ nestloop(babel_3293_t1 babel_3293_t2) nestloop(babel_3293_t1 babel_3293_t2 babel_3293_t3) leading(babel_3293_t1 babel_3293_t2 babel_3293_t3)*/ * from babel_3293_t1 left outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t3.a3) + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 + Index Cond: (a3 = babel_3293_t2.a2) + Filter: (b3 = 1) +~~END~~ + + +select * from babel_3293_t1 left outer merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner loop join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2) nestloop(babel_3293_t1 babel_3293_t2 babel_3293_t3) leading(babel_3293_t1 babel_3293_t2 babel_3293_t3)*/ * from babel_3293_t1 left outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t3.a3) + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 + Index Cond: (a3 = babel_3293_t2.a2) + Filter: (b3 = 1) +~~END~~ + + +select * from babel_3293_t1 t1 left outer merge join babel_3293_t2 t2 on t1.a1 = t2.a2 inner loop join babel_3293_t3 t3 on t2.a2 = t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(t1 t2) nestloop(t1 t2 t3) leading(t1 t2 t3)*/ * from babel_3293_t1 t1 left outer join babel_3293_t2 t2 on t1.a1 = t2.a2 inner join babel_3293_t3 t3 on t2.a2 = t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (t1.a1 = t3.a3) + -> Merge Join + Merge Cond: (t1.a1 = t2.a2) + -> Sort + Sort Key: t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 t3 + Index Cond: (a3 = t2.a2) + Filter: (b3 = 1) +~~END~~ + + +select * from babel_3293_t1, babel_3293_t2 inner merge join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where babel_3293_t1.a1=babel_3293_t3.a3 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2 babel_3293_t3) leading(babel_3293_t1 babel_3293_t2 babel_3293_t3)*/ * from babel_3293_t1, babel_3293_t2 inner join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where babel_3293_t1.a1=babel_3293_t3.a3 +Gather + Workers Planned: 3 + -> Merge Join + Merge Cond: (babel_3293_t2.a2 = babel_3293_t3.a3) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Parallel Seq Scan on babel_3293_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 + -> Sort + Sort Key: babel_3293_t3.a3 + -> Seq Scan on babel_3293_t3 +~~END~~ + + +select * from babel_3293_t1 t1, babel_3293_t2 t2 inner merge join babel_3293_t3 t3 on t2.a2 = t3.a3 where t1.a1 = t3.a3 +go +~~START~~ +text +Query Text: select/*+ mergejoin(t1 t2 t3) leading(t1 t2 t3)*/ * from babel_3293_t1 t1, babel_3293_t2 t2 inner join babel_3293_t3 t3 on t2.a2 = t3.a3 where t1.a1 = t3.a3 +Gather + Workers Planned: 3 + -> Merge Join + Merge Cond: (t2.a2 = t3.a3) + -> Sort + Sort Key: t1.a1 + -> Parallel Hash Join + Hash Cond: (t1.a1 = t2.a2) + -> Parallel Seq Scan on babel_3293_t1 t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 t2 + -> Sort + Sort Key: t3.a3 + -> Seq Scan on babel_3293_t3 t3 +~~END~~ + + +select * from babel_3293_t1 t1, babel_3293_t2 t2 inner hash join babel_3293_t3 t3 on t2.a2 = t3.a3 +go +~~START~~ +text +Query Text: select/*+ hashjoin(t1 t2 t3) leading(t1 t2 t3)*/ * from babel_3293_t1 t1, babel_3293_t2 t2 inner join babel_3293_t3 t3 on t2.a2 = t3.a3 +Hash Join + Hash Cond: (t2.a2 = t3.a3) + -> Nested Loop + -> Gather + Workers Planned: 3 + -> Parallel Seq Scan on babel_3293_t1 t1 + -> Materialize + -> Gather + Workers Planned: 3 + -> Parallel Seq Scan on babel_3293_t2 t2 + -> Hash + -> Gather + Workers Planned: 3 + -> Parallel Seq Scan on babel_3293_t3 t3 +~~END~~ + + +select * from BABEL_3293_t1 t1 left outer MERGE join BaBeL_3293_T2 t2 on t1.a1 = t2.a2 InNeR LOOP JOIN bABEL_3293_t3 t3 on t2.a2 = t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(t1 t2) nestloop(t1 t2 t3) leading(t1 t2 t3)*/ * from BABEL_3293_t1 t1 left outer join BaBeL_3293_T2 t2 on t1.a1 = t2.a2 InNeR JOIN bABEL_3293_t3 t3 on t2.a2 = t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (t1.a1 = t3.a3) + -> Merge Join + Merge Cond: (t1.a1 = t2.a2) + -> Sort + Sort Key: t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) + -> Index Scan using babel_3293_t3_pkey on babel_3293_t3 t3 + Index Cond: (a3 = t2.a2) + Filter: (b3 = 1) +~~END~~ + + +-- Join hints through option clause +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 option(hash join) +go +~~START~~ +text +Query Text: select/*+ set(enable_nestloop off) set(enable_mergejoin off) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Hash + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 option(merge join) +go +~~START~~ +text +Query Text: select/*+ set(enable_nestloop off) set(enable_hashjoin off) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 option(loop join) +go +~~START~~ +text +Query Text: select/*+ set(enable_hashjoin off) set(enable_mergejoin off) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 option(merge join) +go +~~START~~ +text +Query Text: select/*+ set(enable_nestloop off) set(enable_hashjoin off) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 3 + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Merge Join + Merge Cond: (babel_3293_t3.a3 = babel_3293_t1.a1) + -> Sort + Sort Key: babel_3293_t3.a3 + -> Parallel Seq Scan on babel_3293_t3 + Filter: (b3 = 1) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from babeL_3293_T1 join BABEL_3293_T2 on babeL_3293_T1.a1 = BABEL_3293_T2.a2 join babEl_3293_t3 on babel_3293_T2.a2 = BABEL_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 option(merge join) +go +~~START~~ +text +Query Text: select/*+ set(enable_nestloop off) set(enable_hashjoin off) */ * from babeL_3293_T1 join BABEL_3293_T2 on babeL_3293_T1.a1 = BABEL_3293_T2.a2 join babEl_3293_t3 on babel_3293_T2.a2 = BABEL_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 3 + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Merge Join + Merge Cond: (babel_3293_t3.a3 = babel_3293_t1.a1) + -> Sort + Sort Key: babel_3293_t3.a3 + -> Parallel Seq Scan on babel_3293_t3 + Filter: (b3 = 1) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +-- Conflicting join hints +select * from babel_3293_t1 inner hash join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 option(merge join) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conflicting JOIN optimizer hints specified)~~ + + +select * from babel_3293_t1 inner hash join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 option(hash join) +go +~~START~~ +text +Query Text: select/*+ hashjoin(babel_3293_t1 babel_3293_t2) set(enable_nestloop off) set(enable_mergejoin off) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Parallel Seq Scan on babel_3293_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 +~~END~~ + + +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 option(merge join, loop join) +go +~~START~~ +text +Query Text: select/*+ set(enable_hashjoin off) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3293_t1 + -> Index Scan using babel_3293_t2_pkey on babel_3293_t2 + Index Cond: (a2 = babel_3293_t1.a1) +~~END~~ + + +select * from babel_3293_t1 inner loop join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 option(merge join) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conflicting JOIN optimizer hints specified)~~ + + +select * from babel_3293_t1 inner loop join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner merge join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 option(merge join) +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conflicting JOIN optimizer hints specified)~~ + + +select * from babel_3293_t1 inner loop join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner merge join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 option(merge join, loop join) +go +~~START~~ +text +Query Text: select/*+ nestloop(babel_3293_t1 babel_3293_t2) mergejoin(babel_3293_t1 babel_3293_t2 babel_3293_t3) set(enable_hashjoin off) leading(babel_3293_t1 babel_3293_t2 babel_3293_t3)*/ * from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 inner join babel_3293_t3 on babel_3293_t2.a2 = babel_3293_t3.a3 where b1 = 1 and b2 = 1 and b3 = 1 +Gather + Workers Planned: 3 + -> Merge Join + Merge Cond: (babel_3293_t3.a3 = babel_3293_t1.a1) + -> Sort + Sort Key: babel_3293_t3.a3 + -> Parallel Seq Scan on babel_3293_t3 + Filter: (b3 = 1) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +-- Queries with both table hints and join hints +select * from babel_3293_t1 with(index(index_babel_3293_t1_b1)) inner loop join babel_3293_t2 (index(index_babel_3293_t2_b2)) on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3293_t1 index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210) indexscan(babel_3293_t2 index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e) nestloop(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e on babel_3293_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 with(index(index_babel_3293_t1_b1)) right outer merge join babel_3293_t2 (index(index_babel_3293_t2_b2)) on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3293_t1 index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210) indexscan(babel_3293_t2 index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e) mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from babel_3293_t1 right outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Index Scan using index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e on babel_3293_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 option(loop join, table hint(babel_3293_t1, index(index_babel_3293_t1_b1)), table hint(babel_3293_t2, index(index_babel_3293_t2_b2))) +go +~~START~~ +text +Query Text: select/*+ indexscan(babel_3293_t1 index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210) indexscan(babel_3293_t2 index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e) set(enable_hashjoin off) set(enable_mergejoin off) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e on babel_3293_t2 + Index Cond: (b2 = 1) +~~END~~ + + +-- Join hints on nested subqueries are not supported +select * from (select distinct a1 as a1 from babel_3293_t1) s1 inner merge join babel_3293_t2 on s1.a1 = babel_3293_t2.a2 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ * from (select distinct a1 as a1 from babel_3293_t1) s1 inner join babel_3293_t2 on s1.a1 = babel_3293_t2.a2 +Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> HashAggregate + Group Key: babel_3293_t1.a1 + -> Gather + Workers Planned: 3 + -> Parallel Seq Scan on babel_3293_t1 + -> Hash + -> Gather + Workers Planned: 3 + -> Parallel Seq Scan on babel_3293_t2 +~~END~~ + + +select * from (select babel_3293_t1.* from babel_3293_t1 inner merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2) s1 inner join (select babel_3293_t1.* from babel_3293_t1 inner hash join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2) s2 on s1.a1 = s2.a1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(babel_3293_t1 babel_3293_t2) hashjoin(babel_3293_t1 babel_3293_t2 babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2 babel_3293_t1 babel_3293_t2)*/ * from (select babel_3293_t1.* from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2) s1 inner join (select babel_3293_t1.* from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2) s2 on s1.a1 = s2.a1 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2_1.a2) + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t1_1.a1) + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Parallel Seq Scan on babel_3293_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t1 babel_3293_t1_1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 babel_3293_t2_1 +~~END~~ + + +-- Test FORCE ORDER hints +/** + * Run a SELECT query with multiple joins such that the join order indicated by the query syntax is not preserved during query optimization. + * This ensures that when the FORCE ORDER query hint is given in the test below, the join order is preserved. + * If the join order was to be preserved even without the hint, the next test would not prove that the FORCE ORDER hint is working. + */ +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t1.b1 = babel_3293_t3.b3 +go +~~START~~ +text +Query Text: select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t1.b1 = babel_3293_t3.b3 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.b1 = babel_3293_t3.b3) + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Parallel Seq Scan on babel_3293_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t3 +~~END~~ + + +/* + * Run the above SELECT query and give the FORCE ORDER query hint to make sure that the join order is preserved + */ +select * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t1.b1 = babel_3293_t3.b3 option(force order) +go +~~START~~ +text +Query Text: select/*+ set(join_collapse_limit 1) */ * from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 join babel_3293_t3 on babel_3293_t1.b1 = babel_3293_t3.b3 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.b1 = babel_3293_t3.b3) + -> Parallel Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Parallel Seq Scan on babel_3293_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t3 +~~END~~ + + +-- UPDATE and DELETE queries with join hints needs to be revisited later. pg_hint_plan is currently not following the given join hints +-- Test UPDATE queries with and without hints +update babel_3293_t1 set a1 = 1 from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: update babel_3293_t1 set a1 = 1 from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Update on babel_3293_t1 + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Hash + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +update babel_3293_t1 set a1 = 1 from babel_3293_t1 inner merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: update/*+ mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ babel_3293_t1 set a1 = 1 from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Update on babel_3293_t1 + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +update babel_3293_t1 set a1 = 1 from babel_3293_t1 with(index(index_babel_3293_t1_b1)) full outer merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: update/*+ indexscan(babel_3293_t1 index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210) mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ babel_3293_t1 set a1 = 1 from babel_3293_t1 full outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Update on babel_3293_t1 + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 + Index Cond: (b1 = 1) + Filter: (ctid IS NOT NULL) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +-- Test DELETE queries with and without hints +delete babel_3293_t1 from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: delete babel_3293_t1 from babel_3293_t1 join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Delete on babel_3293_t1 + -> Hash Join + Hash Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Hash + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +delete babel_3293_t1 from babel_3293_t1 inner merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: delete/*+ mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ babel_3293_t1 from babel_3293_t1 inner join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Delete on babel_3293_t1 + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Bitmap Heap Scan on babel_3293_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +delete babel_3293_t1 from babel_3293_t1 with(index(index_babel_3293_t1_b1)) left outer merge join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: delete/*+ indexscan(babel_3293_t1 index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210) mergejoin(babel_3293_t1 babel_3293_t2) leading(babel_3293_t1 babel_3293_t2)*/ babel_3293_t1 from babel_3293_t1 left outer join babel_3293_t2 on babel_3293_t1.a1 = babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Delete on babel_3293_t1 + -> Merge Join + Merge Cond: (babel_3293_t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: babel_3293_t1.a1 + -> Index Scan using index_babel_3293_t1_b1babel_329dabb714f0f2c475b9c9e7d1d90cbd210 on babel_3293_t1 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- cleanup +drop table babel_3293_t1 +go + +drop table babel_3293_t2 +go + +drop table babel_3293_t3 +go + +-- Test all queries by specifying a database and schema name +use tempdb +go + +drop table if exists babel_3293_schema.t1 +go + +drop table if exists babel_3293_t2 +go + +drop table if exists babel_3293_t3 +go + +drop schema if exists babel_3293_schema +go + +create schema babel_3293_schema +go + +create table babel_3293_schema.t1(a1 int PRIMARY KEY, b1 int) +go + +create index index_babel_3293_schema_t1_b1 on babel_3293_schema.t1(b1) +go + +create table babel_3293_t2(a2 int PRIMARY KEY, b2 int) +go + +create index index_babel_3293_t2_b2 on babel_3293_t2(b2) +go + +create table babel_3293_t3(a3 int PRIMARY KEY, b3 int) +go + +set babelfish_showplan_all on +go + +select * from tempdb.babel_3293_schema.t1 inner merge join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 where b1 = 1 and b2 = 1 +go +~~START~~ +text +Query Text: select/*+ mergejoin(t1 babel_3293_t2) leading(t1 babel_3293_t2)*/ * from tempdb.babel_3293_schema.t1 inner join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: t1.a1 + -> Bitmap Heap Scan on t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3293_schema_t1_b1t1baa4a261b22c51c48cc060f8d390c3e9 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Bitmap Heap Scan on babel_3293_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3293_schema.t1 with(index(index_babel_3293_schema_t1_b1)) join tempdb.dbo.babel_3293_t2 (index(index_babel_3293_t2_b2)) on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 where b1 = 1 and b2 = 1 -- Join query with just table hints +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3293_schema_t1_b1t1baa4a261b22c51c48cc060f8d390c3e9) indexscan(babel_3293_t2 index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e) */ * from tempdb.babel_3293_schema.t1 join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Hash Join + Hash Cond: (t1.a1 = babel_3293_t2.a2) + -> Index Scan using index_babel_3293_schema_t1_b1t1baa4a261b22c51c48cc060f8d390c3e9 on t1 + Index Cond: (b1 = 1) + -> Hash + -> Index Scan using index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e on babel_3293_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3293_schema.t1 join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 where b1 = 1 and b2 = 1 option(merge join, table hint(tempdb.babel_3293_schema.t1, index(index_babel_3293_schema_t1_b1)), table hint(tempdb.dbo.babel_3293_t2, index(index_babel_3293_t2_b2))) +go +~~START~~ +text +Query Text: select/*+ indexscan(t1 index_babel_3293_schema_t1_b1t1baa4a261b22c51c48cc060f8d390c3e9) indexscan(babel_3293_t2 index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e) set(enable_nestloop off) set(enable_hashjoin off) */ * from tempdb.babel_3293_schema.t1 join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 where b1 = 1 and b2 = 1 +Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (t1.a1 = babel_3293_t2.a2) + -> Sort + Sort Key: t1.a1 + -> Index Scan using index_babel_3293_schema_t1_b1t1baa4a261b22c51c48cc060f8d390c3e9 on t1 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3293_t2.a2 + -> Index Scan using index_babel_3293_t2_b2babel_329ea1aa3a9e72f8fece1b90ee8c2a8f24e on babel_3293_t2 + Index Cond: (b2 = 1) +~~END~~ + + +select * from tempdb.babel_3293_schema.t1 join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 join tempdb.dbo.babel_3293_t3 on tempdb.babel_3293_schema.t1.b1 = tempdb.dbo.babel_3293_t3.b3 option(force order) +go +~~START~~ +text +Query Text: select/*+ set(join_collapse_limit 1) */ * from tempdb.babel_3293_schema.t1 join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 join tempdb.dbo.babel_3293_t3 on tempdb.babel_3293_schema.t1.b1 = tempdb.dbo.babel_3293_t3.b3 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (t1.b1 = babel_3293_t3.b3) + -> Parallel Hash Join + Hash Cond: (t1.a1 = babel_3293_t2.a2) + -> Parallel Seq Scan on t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t2 + -> Parallel Hash + -> Parallel Seq Scan on babel_3293_t3 +~~END~~ + + +select * from tempdb.babel_3293_schema.t1 inner loop join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 left outer merge join tempdb.dbo.babel_3293_t3 on tempdb.babel_3293_schema.t1.b1 = tempdb.dbo.babel_3293_t3.b3 +go +~~START~~ +text +Query Text: select/*+ nestloop(t1 babel_3293_t2) mergejoin(t1 babel_3293_t2 babel_3293_t3) leading(t1 babel_3293_t2 babel_3293_t3)*/ * from tempdb.babel_3293_schema.t1 inner join tempdb.dbo.babel_3293_t2 on tempdb.babel_3293_schema.t1.a1 = tempdb.dbo.babel_3293_t2.a2 left outer join tempdb.dbo.babel_3293_t3 on tempdb.babel_3293_schema.t1.b1 = tempdb.dbo.babel_3293_t3.b3 +Gather + Workers Planned: 3 + -> Merge Left Join + Merge Cond: (t1.b1 = babel_3293_t3.b3) + -> Sort + Sort Key: t1.b1 + -> Nested Loop + -> Parallel Seq Scan on t1 + -> Index Scan using babel_3293_t2_pkey on babel_3293_t2 + Index Cond: (a2 = t1.a1) + -> Sort + Sort Key: babel_3293_t3.b3 + -> Seq Scan on babel_3293_t3 +~~END~~ + + +set babelfish_showplan_all off +go + +-- cleanup +drop table babel_3293_schema.t1 +go + +drop table babel_3293_t2 +go + +drop table babel_3293_t3 +go + +drop schema babel_3293_schema +go diff --git a/test/JDBC/expected/parallel_query/BABEL-3294.out b/test/JDBC/expected/parallel_query/BABEL-3294.out new file mode 100644 index 0000000000..50d7ff3520 --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-3294.out @@ -0,0 +1,156 @@ +drop table if exists babel_3294_t1 +go + +create table babel_3294_t1(a1 int) +go + +alter table babel_3294_t1 set (parallel_workers = 16) +go + +-- Encourage use of parallel plans +select set_config('force_parallel_mode', '1', false) +go +~~START~~ +text +on +~~END~~ + + +select set_config('parallel_setup_cost', '0', false) +go +~~START~~ +text +0 +~~END~~ + + +select set_config('parallel_tuple_cost', '0', false) +go +~~START~~ +text +0 +~~END~~ + + +select set_config('babelfishpg_tsql.enable_pg_hint', 'on', false); +go +~~START~~ +text +on +~~END~~ + + +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +set babelfish_showplan_all on +go + +/* + * Run a SELECT query without any hints to ensure that un-hinted queries still work + * It uses 2 workers as it is the deault value for the GUC max_parallel_workers_per_gather + */ +select * from babel_3294_t1 t1 where a1 = 1 +go +~~START~~ +text +Query Text: select * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 4 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +/* + * The MAXDOP hint should be handled specially the hint value is 0 + * This is because in T-SQL, setting MAXDOP to 0 allows SQL Server to use all the available processors up to 64 processors + * However, if we set the GUC max_parallel_workers_per_gather to 0, it disables parallelism in P-SQL + * Thus, we need to set the GUC value to 64 instead. The planner however will use 16 workers as we only have 16 workers available + */ +select * from babel_3294_t1 t1 where a1 = 1 option(maxdop 0) +go +~~START~~ +text +Query Text: select/*+ set(max_parallel_workers_per_gather 64) */ * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 16 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +/* + * Run SELECT queries and give the MAXDOP hint with different values to verify the hint is actually getting mapped + */ +select * from babel_3294_t1 t1 where a1 = 1 option(maxdop 1) +go +~~START~~ +text +Query Text: select/*+ set(max_parallel_workers_per_gather 1) */ * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 1 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +select * from babel_3294_t1 t1 where a1 = 1 option(maxdop 2) +go +~~START~~ +text +Query Text: select/*+ set(max_parallel_workers_per_gather 2) */ * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 2 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +select * from babel_3294_t1 t1 where a1 = 1 option(maxdop 4) +go +~~START~~ +text +Query Text: select/*+ set(max_parallel_workers_per_gather 4) */ * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 4 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +select * from babel_3294_t1 t1 where a1 = 1 option(maxdop 8) +go +~~START~~ +text +Query Text: select/*+ set(max_parallel_workers_per_gather 8) */ * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 8 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +select * from babel_3294_t1 t1 where a1 = 1 option(maxdop 16) +go +~~START~~ +text +Query Text: select/*+ set(max_parallel_workers_per_gather 16) */ * from babel_3294_t1 t1 where a1 = 1 +Gather + Workers Planned: 16 + -> Parallel Seq Scan on babel_3294_t1 t1 + Filter: (a1 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- cleanup +drop table babel_3294_t1 +go diff --git a/test/JDBC/expected/parallel_query/BABEL-3512.out b/test/JDBC/expected/parallel_query/BABEL-3512.out new file mode 100644 index 0000000000..7e0fe69485 --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-3512.out @@ -0,0 +1,929 @@ + +/* + * Test stored procs WITH hints. All tests examine the query plan AND the + * pg_proc table to ensure that subsequent connections will be using the correct + * query. +*/ +DROP TABLE IF EXISTS babel_3512_t1 +GO + +DROP TABLE IF EXISTS babel_3512_t2 +GO + +DROP TABLE IF EXISTS babel_3512_t3 +GO + +DROP procedure IF EXISTS babel_3512_proc_1 +GO + +DROP procedure IF EXISTS babel_3512_proc_2 +GO + +DROP procedure IF EXISTS babel_3512_proc_3 +GO + +DROP procedure IF EXISTS babel_3512_proc_4 +GO + +DROP procedure IF EXISTS babel_3512_proc_5 +GO + +DROP procedure IF EXISTS babel_3512_proc_6 +GO + +DROP procedure IF EXISTS babel_3512_proc_7 +GO + +DROP procedure IF EXISTS babel_3512_proc_8 +GO + +DROP procedure IF EXISTS babel_3512_proc_9 +GO + +DROP procedure IF EXISTS babel_3512_proc_10 +GO + +DROP procedure IF EXISTS babel_3512_proc_conflict_1 +GO + +DROP procedure IF EXISTS babel_3512_proc_conflict_2 +GO + +DROP procedure IF EXISTS babel_3512_comment_test_1 +GO + +DROP procedure IF EXISTS babel_3512_comment_test_2 +GO + +CREATE TABLE babel_3512_t1(a1 int PRIMARY KEY, b1 int, c1 int) +GO + +CREATE INDEX index_babel_3512_t1_b1 ON babel_3512_t1(b1) +GO + +CREATE INDEX index_babel_3512_t1_c1 ON babel_3512_t1(c1) +GO + +CREATE TABLE babel_3512_t2(a2 int PRIMARY KEY, b2 int, c2 int) +GO + +CREATE TABLE babel_3512_t3(a3 int PRIMARY KEY, b3 int, c3 int) +GO + +CREATE INDEX index_babel_3512_t2_b2 ON babel_3512_t2(b2) +GO + +SELECT set_config('babelfishpg_tsql.explain_costs', 'off', false) +GO +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.enable_pg_hint', 'on', false); +go +~~START~~ +text +on +~~END~~ + + +-- Test one line stored procs WITH join hints +CREATE PROCEDURE babel_3512_proc_1 AS SELECT babel_3512_t1.a1 FROM babel_3512_t1 inner hash join babel_3512_t2 ON a1 = b2 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_1'; +GO +~~START~~ +text +SELECT/*+ hashjoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ babel_3512_t1.a1 FROM babel_3512_t1 inner join babel_3512_t2 ON a1 = b2 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_1 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_1 + Query Text: SELECT/*+ hashjoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ babel_3512_t1.a1 FROM babel_3512_t1 inner join babel_3512_t2 ON a1 = b2 + -> Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3512_t2.b2 = babel_3512_t1.a1) + -> Parallel Seq Scan on babel_3512_t2 + -> Parallel Hash + -> Parallel Seq Scan on babel_3512_t1 +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test multi line stored procs WITH join hints +CREATE PROCEDURE babel_3512_proc_2 AS +SELECT * FROM babel_3512_t1 inner hash join babel_3512_t2 ON a1 = b2 +SELECT * FROM babel_3512_t2 inner loop join babel_3512_t1 ON babel_3512_t1.c1 = babel_3512_t2.c2 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_2'; +GO +~~START~~ +text +SELECT/*+ hashjoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON a1 = b2SELECT/*+ nestloop(babel_3512_t2 babel_3512_t1) leading(babel_3512_t2 babel_3512_t1)*/ * FROM babel_3512_t2 inner join babel_3512_t1 ON babel_3512_t1.c1 = babel_3512_t2.c2 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_2 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_2 + Query Text: SELECT/*+ hashjoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON a1 = b2 + -> Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3512_t2.b2 = babel_3512_t1.a1) + -> Parallel Seq Scan on babel_3512_t2 + -> Parallel Hash + -> Parallel Seq Scan on babel_3512_t1 + Query Text: SELECT/*+ nestloop(babel_3512_t2 babel_3512_t1) leading(babel_3512_t2 babel_3512_t1)*/ * FROM babel_3512_t2 inner join babel_3512_t1 ON babel_3512_t1.c1 = babel_3512_t2.c2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t2 + -> Index Scan using index_babel_3512_t1_c1babel_35191aab574110138d8b9ec599810282a81 on babel_3512_t1 + Index Cond: (c1 = babel_3512_t2.c2) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test one line stored procs WITH index hints +CREATE PROCEDURE babel_3512_proc_3 AS +SELECT * FROM babel_3512_t1 (index(index_babel_3512_t1_b1)) WHERE b1 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_3'; +GO +~~START~~ +text +SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_3 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_3 + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test multple line stored procs WITH index hints +CREATE PROCEDURE babel_3512_proc_4 AS +SELECT * FROM babel_3512_t1 (index(index_babel_3512_t1_b1)) WHERE b1 = 1 +SELECT * FROM babel_3512_t1 WITH(index(index_babel_3512_t1_b1)) WHERE b1 = 1 +SELECT * FROM babel_3512_t1 WHERE b1 = 3 OPTION(table hint(babel_3512_t1, index(index_babel_3512_t1_b1))) +SELECT * FROM babel_3512_t1 WITH(index=index_babel_3512_t1_b1) WHERE b1 = 1 UNION SELECT * FROM babel_3512_t2 WITH(index=index_babel_3512_t2_b2) WHERE b2 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_4'; +GO +~~START~~ +text +SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 1SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 1SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 3 SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1 WHERE b1 = 1 UNION SELECT * FROM babel_3512_t2 WHERE b2 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_4 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_4 + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ * FROM babel_3512_t1 WHERE b1 = 3 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 3) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1 WHERE b1 = 1 UNION SELECT * FROM babel_3512_t2 WHERE b2 = 1 + -> HashAggregate + Group Key: babel_3512_t1.a1, babel_3512_t1.b1, babel_3512_t1.c1 + -> Gather + Workers Planned: 2 + -> Parallel Append + -> Parallel Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Parallel Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test CTE Queries single line +CREATE PROCEDURE babel_3512_proc_5 AS +WITH babel_3512_t1_cte (a1, b1, c1) as (SELECT * FROM babel_3512_t1 WITH(index=index_babel_3512_t1_b1) WHERE b1 = 1) SELECT * FROM babel_3512_t1_cte WHERE c1 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_5'; +GO +~~START~~ +text +WITH/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ babel_3512_t1_cte (a1, b1, c1) as (SELECT * FROM babel_3512_t1 WHERE b1 = 1) SELECT * FROM babel_3512_t1_cte WHERE c1 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_5 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_5 + Query Text: WITH/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ babel_3512_t1_cte (a1, b1, c1) as (SELECT * FROM babel_3512_t1 WHERE b1 = 1) SELECT * FROM babel_3512_t1_cte WHERE c1 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + Filter: (c1 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test CTE Queries multi-line +CREATE PROCEDURE babel_3512_proc_6 AS +WITH babel_3512_t1_cte (a1, b1, c1) as (SELECT * FROM babel_3512_t1 WITH(index=index_babel_3512_t1_b1) WHERE b1 = 1) SELECT * FROM babel_3512_t1_cte WHERE c1 = 1 +WITH babel_3512_t2_cte (a1, b2, c2) as (SELECT * FROM babel_3512_t2 WITH(index=index_babel_3512_t2_b1) WHERE b2 = 1) SELECT * FROM babel_3512_t2_cte WHERE c2 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_6'; +GO +~~START~~ +text +WITH/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ babel_3512_t1_cte (a1, b1, c1) as (SELECT * FROM babel_3512_t1 WHERE b1 = 1) SELECT * FROM babel_3512_t1_cte WHERE c1 = 1WITH/*+ indexscan(babel_3512_t2 index_babel_3512_t2_b1babel_351ed65eb34ef55dec01b20e7fff9c5ca06) */ babel_3512_t2_cte (a1, b2, c2) as (SELECT * FROM babel_3512_t2 WHERE b2 = 1) SELECT * FROM babel_3512_t2_cte WHERE c2 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +-- the purpose of babel_3512_t2_cte is to check the behavior for invalid hint +EXEC babel_3512_proc_6 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_6 + Query Text: WITH/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) */ babel_3512_t1_cte (a1, b1, c1) as (SELECT * FROM babel_3512_t1 WHERE b1 = 1) SELECT * FROM babel_3512_t1_cte WHERE c1 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + Filter: (c1 = 1) + Query Text: WITH/*+ indexscan(babel_3512_t2 index_babel_3512_t2_b1babel_351ed65eb34ef55dec01b20e7fff9c5ca06) */ babel_3512_t2_cte (a1, b2, c2) as (SELECT * FROM babel_3512_t2 WHERE b2 = 1) SELECT * FROM babel_3512_t2_cte WHERE c2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Bitmap Heap Scan on babel_3512_t2 + Recheck Cond: (b2 = 1) + Filter: (c2 = 1) + -> Bitmap Index Scan on index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 + Index Cond: (b2 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test table hints single line +CREATE PROCEDURE babel_3512_proc_7 AS +SELECT * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 OPTION(table hint(babel_3512_t1, index(index_babel_3512_t1_b1)), table hint(babel_3512_t2, index(index_babel_3512_t2_b2))) +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_7'; +GO +~~START~~ +text +SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_7 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_7 + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test table hints multi line +CREATE PROCEDURE babel_3512_proc_8 AS +SELECT * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 +SELECT * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 OPTION(table hint(babel_3512_t1, index(index_babel_3512_t1_b1)), table hint(babel_3512_t2, index(index_babel_3512_t2_b2))) +SELECT * FROM babel_3512_t1 babel_3512_t1 WITH(index=index_babel_3512_t1_b1), babel_3512_t2 babel_3512_t2 WITH(index=index_babel_3512_t2_b2) WHERE b1 = 1 AND b2 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_8'; +GO +~~START~~ +text +SELECT * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1 babel_3512_t1 , babel_3512_t2 babel_3512_t2 WHERE b1 = 1 AND b2 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_8 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_8 + Query Text: SELECT * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Bitmap Heap Scan on babel_3512_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a + Index Cond: (b1 = 1) + -> Materialize + -> Bitmap Heap Scan on babel_3512_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 + Index Cond: (b2 = 1) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1, babel_3512_t2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) */ * FROM babel_3512_t1 babel_3512_t1 , babel_3512_t2 babel_3512_t2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO +-- Test multiple hints combined single line +CREATE PROCEDURE babel_3512_proc_9 AS +SELECT * FROM babel_3512_t1 WITH(index(index_babel_3512_t1_b1)) inner loop join babel_3512_t2 (index(index_babel_3512_t2_b2)) ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_9'; +GO +~~START~~ +text +SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_9 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_9 + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO +-- Test multiple hints combined multi-line +CREATE PROCEDURE babel_3512_proc_10 AS +SELECT * FROM babel_3512_t1 join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 +SELECT * FROM babel_3512_t1 join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 OPTION(loop join, table hint(babel_3512_t1, index(index_babel_3512_t1_b1)), table hint(babel_3512_t2, index(index_babel_3512_t2_b2))) +SELECT * FROM babel_3512_t1 WITH(index(index_babel_3512_t1_b1)) right outer merge join babel_3512_t2 (index(index_babel_3512_t2_b2)) ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_proc_10'; +GO +~~START~~ +text +SELECT * FROM babel_3512_t1 join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) set(enable_hashjoin off) set(enable_mergejoin off) */ * FROM babel_3512_t1 join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) mergejoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ * FROM babel_3512_t1 right outer join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_proc_10 +GO +~~START~~ +text +Query Text: EXEC babel_3512_proc_10 + Query Text: SELECT * FROM babel_3512_t1 join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 2 + -> Nested Loop + -> Parallel Bitmap Heap Scan on babel_3512_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a + Index Cond: (b1 = 1) + -> Memoize + Cache Key: babel_3512_t1.a1 + Cache Mode: logical + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) + Filter: (b2 = 1) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) set(enable_hashjoin off) set(enable_mergejoin off) */ * FROM babel_3512_t1 join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + Join Filter: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) + Query Text: SELECT/*+ indexscan(babel_3512_t1 index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a) indexscan(babel_3512_t2 index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9) mergejoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ * FROM babel_3512_t1 right outer join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 WHERE b1 = 1 AND b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Merge Join + Merge Cond: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Sort + Sort Key: babel_3512_t1.a1 + -> Index Scan using index_babel_3512_t1_b1babel_351c4a7795e05c8f14a17174b8ca33d439a on babel_3512_t1 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3512_t2.a2 + -> Index Scan using index_babel_3512_t2_b2babel_351e39a010b48f9dda93369af0e37b7b7e9 on babel_3512_t2 + Index Cond: (b2 = 1) +~~END~~ + + +SET babelfish_showplan_all OFF +GO + +-- Test conflicting hints raises error +CREATE PROCEDURE babel_3512_proc_conflict_1 AS +SELECT * FROM babel_3512_t1 inner hash join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 OPTION(merge join) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conflicting JOIN optimizer hints specified)~~ + + +EXEC babel_3512_proc_conflict_1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure babel_3512_proc_conflict_1() does not exist)~~ + + +-- Test conflicting hints in multi-line stored proc raises error +CREATE PROCEDURE babel_3512_proc_conflict_2 AS +SELECT * FROM babel_3512_t1 inner hash join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +SELECT * FROM babel_3512_t1 inner hash join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 OPTION(merge join) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conflicting JOIN optimizer hints specified)~~ + + +EXEC babel_3512_proc_conflict_2 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: procedure babel_3512_proc_conflict_2() does not exist)~~ + + +SET babelfish_showplan_all ON +GO + +-- Test hints with comment blocks +SELECT/* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Parallel Seq Scan on babel_3512_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3512_t2 +~~END~~ + + +SELECT/* this is a comment block */ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +SELECT /* this is a comment block */ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ /* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +SELECT /* this is a comment block */ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ /* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +SELECT +* +FROM +babel_3512_t1 +inner +hash +join +babel_3512_t2 +ON +babel_3512_t1.a1 += +babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ hashjoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ +* +FROM +babel_3512_t1 +inner + +join +babel_3512_t2 +ON +babel_3512_t1.a1 += +babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Parallel Seq Scan on babel_3512_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3512_t2 +~~END~~ + + +SELECT/*test*/SUM(1) +GO +~~START~~ +text +Query Text: SELECT/*test*/SUM(1) +Gather + Workers Planned: 1 + Single Copy: true + -> Aggregate + -> Result +~~END~~ + + +SELECT/*this is a comment block*/*FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/*FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +/* this is another comment block */SELECT/*this is a comment block*/* FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/* FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +/* this is another comment block *//*thisisanothercommentblock*/SELECT/*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +/* this is another comment block *//* this is another comment block */SELECT/*this is a comment block1234*//*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block1234*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + +SELECT/*this is a comment + multi line block */ + /*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO +~~START~~ +text +Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment + multi line block */ + /*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +-- Test hints with comment blocks in stored procs +SET babelfish_showplan_all OFF +GO + +CREATE PROCEDURE babel_3512_comment_test_1 AS +SELECT/* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +SELECT/* this is a comment block */ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +SELECT /* this is a comment block */ * FROM + babel_3512_t1 inner merge join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +SELECT/*this is a comment block*/*FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +/* this is another comment block */SELECT/*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_comment_test_1'; +GO +~~START~~ +text +SELECT/* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2SELECT/*+ mergejoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ /* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/*FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2/* this is another comment block */SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +~~END~~ + + +CREATE PROCEDURE babel_3512_comment_test_2 AS +/* this is another comment block *//*thisisanothercommentblock*/SELECT/*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +/* this is another comment block *//* this is another comment block */SELECT/*this is a comment block1234*//*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +SELECT/*this is a comment + multi line block */ + /*this is a comment block*/ * FROM babel_3512_t1 inner loop join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3512_comment_test_2'; +GO +~~START~~ +text +SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2/* this is another comment block *//* this is another comment block */SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block1234*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment multi line block */ /*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 +~~END~~ + + +SET babelfish_showplan_all ON +GO + +EXEC babel_3512_comment_test_1 +GO +~~START~~ +text +Query Text: EXEC babel_3512_comment_test_1 + Query Text: SELECT/* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Parallel Hash Join + Hash Cond: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Parallel Seq Scan on babel_3512_t1 + -> Parallel Hash + -> Parallel Seq Scan on babel_3512_t2 + Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//* this is a comment block */ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) + Query Text: SELECT/*+ mergejoin(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*/ /* this is a comment block */ * FROM + babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 1 + -> Merge Join + Merge Cond: (babel_3512_t1.a1 = babel_3512_t2.a2) + -> Parallel Index Scan using babel_3512_t1_pkey on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/*FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) + Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +EXEC babel_3512_comment_test_2 +GO +~~START~~ +text +Query Text: EXEC babel_3512_comment_test_2 + Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) + Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment block1234*//*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) + Query Text: SELECT/*+ nestloop(babel_3512_t1 babel_3512_t2) leading(babel_3512_t1 babel_3512_t2)*//*this is a comment + multi line block */ + /*this is a comment block*/ * FROM babel_3512_t1 inner join babel_3512_t2 ON babel_3512_t1.a1 = babel_3512_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3512_t1 + -> Index Scan using babel_3512_t2_pkey on babel_3512_t2 + Index Cond: (a2 = babel_3512_t1.a1) +~~END~~ + + +-- clean up +SET babelfish_showplan_all OFF +GO + +DROP PROCEDURE babel_3512_proc_1 +GO + +DROP PROCEDURE babel_3512_proc_2 +GO + +DROP PROCEDURE babel_3512_proc_3 +GO + +DROP PROCEDURE babel_3512_proc_4 +GO + +DROP PROCEDURE babel_3512_proc_5 +GO + +DROP PROCEDURE babel_3512_proc_6 +GO + +DROP PROCEDURE babel_3512_proc_7 +GO + +DROP PROCEDURE babel_3512_proc_8 +GO + +DROP PROCEDURE babel_3512_proc_9 +GO + +DROP PROCEDURE babel_3512_proc_10 +GO + +DROP procedure IF EXISTS babel_3512_proc_conflict_1 +GO + +DROP procedure IF EXISTS babel_3512_proc_conflict_2 +GO + +DROP procedure IF EXISTS babel_3512_comment_test_1 +GO + +DROP procedure IF EXISTS babel_3512_comment_test_2 +GO + +DROP TABLE babel_3512_t1 +GO + +DROP TABLE babel_3512_t2 +GO + +DROP TABLE babel_3512_t3 +GO diff --git a/test/JDBC/expected/parallel_query/BABEL-3592.out b/test/JDBC/expected/parallel_query/BABEL-3592.out new file mode 100644 index 0000000000..cc8e17be0b --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-3592.out @@ -0,0 +1,450 @@ +drop procedure if exists babel_3592_insert_multiline +go + +drop table if exists babel_3592_t1 +go + +drop table if exists babel_3592_t2 +go + +drop table if exists babel_3592_t3 +go + +create table babel_3592_t1(a1 int PRIMARY KEY, b1 int) +go + +create index index_babel_3592_t1_b1 on babel_3592_t1(b1) +go + +create table babel_3592_t2(a2 int PRIMARY KEY, b2 int) +go + +create index index_babel_3592_t2_b2 on babel_3592_t2(b2) +go + +create table babel_3592_t3(a3 int PRIMARY KEY, b3 int) +go + +select set_config('babelfishpg_tsql.explain_costs', 'off', false) +go +~~START~~ +text +off +~~END~~ + + +select set_config('babelfishpg_tsql.enable_pg_hint', 'on', false); +go +~~START~~ +text +on +~~END~~ + + +-- TEST INSERT queries +CREATE PROCEDURE babel_3592_insert_multiline AS +insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 +insert into babel_3592_t2 + select * + from babel_3592_t1 with(index(index_babel_3592_t1_b1)) + where b1 = 1 +insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3592_insert_multiline'; +GO +~~START~~ +text +insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 +~~END~~ + + +CREATE PROCEDURE babel_3592_insert_singleline AS insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +GO + +EXEC babel_3592_insert_multiline +GO + +EXEC babel_3592_insert_singleline +GO + +set babelfish_showplan_all on +go + +EXEC babel_3592_insert_multiline +GO +~~START~~ +text +Query Text: EXEC babel_3592_insert_multiline + Query Text: insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Bitmap Heap Scan on babel_3592_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 + select * + from babel_3592_t1 + where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) +~~END~~ + + +EXEC babel_3592_insert_singleline +GO +~~START~~ +text +Query Text: EXEC babel_3592_insert_singleline + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- Test UPDATE queries +CREATE PROCEDURE babel_3592_updates_multiline AS +update babel_3592_t1 + set a1 = 1 where b1 = 1 +update babel_3592_t1 + with(index(index_babel_3592_t1_b1)) + set a1 = 1 where b1 = 1 +update babel_3592_t1 set a1 = 1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +GO + +CREATE PROCEDURE babel_3592_updates_singleline AS update babel_3592_t1 set a1 = 1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3592_updates_multiline'; +GO +~~START~~ +text +update babel_3592_t1 set a1 = 1 where b1 = 1update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 +~~END~~ + + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3592_updates_singleline'; +GO +~~START~~ +text +update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 +~~END~~ + + +EXEC babel_3592_insert_multiline +GO + +EXEC babel_3592_updates_singleline +GO + +set babelfish_showplan_all on +go + +EXEC babel_3592_insert_multiline +GO +~~START~~ +text +Query Text: EXEC babel_3592_insert_multiline + Query Text: insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Bitmap Heap Scan on babel_3592_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 + select * + from babel_3592_t1 + where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) +~~END~~ + + +EXEC babel_3592_updates_singleline +GO +~~START~~ +text +Query Text: EXEC babel_3592_updates_singleline + Query Text: update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 + -> Update on babel_3592_t1 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + +-- Test DELETE queries with and without hints +CREATE PROCEDURE babel_3592_delete_multiline AS +delete from babel_3592_t1 where b1 = 1 +delete from babel_3592_t1 with + (index + (index_babel_3592_t1_b1) + ) + where b1 = 1 +delete from babel_3592_t1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +GO + +CREATE PROCEDURE babel_3592_delete_singleline AS delete from babel_3592_t1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3592_delete_multiline'; +GO +~~START~~ +text +delete from babel_3592_t1 where b1 = 1delete/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ from babel_3592_t1 where b1 = 1delete/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ from babel_3592_t1 where b1 = 1 +~~END~~ + + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3592_delete_singleline'; +GO +~~START~~ +text +delete/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ from babel_3592_t1 where b1 = 1 +~~END~~ + + +EXEC babel_3592_insert_multiline +GO + +EXEC babel_3592_delete_singleline +GO + +set babelfish_showplan_all on +go + +EXEC babel_3592_insert_multiline +GO +~~START~~ +text +Query Text: EXEC babel_3592_insert_multiline + Query Text: insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Bitmap Heap Scan on babel_3592_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 + select * + from babel_3592_t1 + where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) +~~END~~ + + +EXEC babel_3592_delete_singleline +GO +~~START~~ +text +Query Text: EXEC babel_3592_delete_singleline + Query Text: delete/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ from babel_3592_t1 where b1 = 1 + -> Delete on babel_3592_t1 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) +~~END~~ + + +set babelfish_showplan_all off +go + + + + + +-- Test mixed statements +create procedure babel_3592_proc_mixed_statements AS + update babel_3592_t1 with(index(index_babel_3592_t1_b1)) set a1 = 1 where b1 = 1 + select * from babel_3592_t1 inner loop join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 + select * from babel_3592_t1 inner merge + join babel_3592_t2 + on babel_3592_t1.a1 = babel_3592_t2.a2 + update babel_3592_t1 set a1 = 1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) + delete babel_3592_t1 from babel_3592_t1 inner merge join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 where b1 = 1 and b2 = 1 +delete babel_3592_t1 from babel_3592_t1 with(index(index_babel_3592_t1_b1)) left outer merge join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 where b1 = 1 and b2 = 1 +insert +into +babel_3592_t2 select * from babel_3592_t1 where b1 = 1 +insert into babel_3592_t2 select * from babel_3592_t1 with(index(index_babel_3592_t1_b1)) where b1 = 1 +insert into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 option(table hint(babel_3592_t1, index(index_babel_3592_t1_b1))) +-- comments inside the stored proc +update babel_3592_t1 set a1 = 1 where b1 = 1 +/* + *multiline comment + */ + select * from babel_3592_t1 with(index(index_babel_3592_t1_b1)), babel_3592_t2 with(index(index_babel_3592_t2_b2)) where b1 = 1 and b2 = 1 +GO + +SELECT prosrc FROM pg_proc WHERE proname = 'babel_3592_proc_mixed_statements'; +GO +~~START~~ +text +update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 select/*+ nestloop(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ * from babel_3592_t1 inner join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 select/*+ mergejoin(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ * from babel_3592_t1 inner join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 delete/*+ mergejoin(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ babel_3592_t1 from babel_3592_t1 inner join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 where b1 = 1 and b2 = 1delete/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) mergejoin(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ babel_3592_t1 from babel_3592_t1 left outer join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 where b1 = 1 and b2 = 1insertintobabel_3592_t2 select * from babel_3592_t1 where b1 = 1insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 -- comments inside the stored procupdate babel_3592_t1 set a1 = 1 where b1 = 1/* *multiline comment */ select/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) indexscan(babel_3592_t2 index_babel_3592_t2_b2babel_359155b730148d8fcf0167f32edb84e3f7d) */ * from babel_3592_t1 , babel_3592_t2 where b1 = 1 and b2 = 1 +~~END~~ + + +EXEC babel_3592_proc_mixed_statements +GO +~~START~~ +int#!#int#!#int#!#int +~~END~~ + +~~START~~ +int#!#int#!#int#!#int +~~END~~ + +~~START~~ +int#!#int#!#int#!#int +~~END~~ + + +set babelfish_showplan_all on +go + +EXEC babel_3592_proc_mixed_statements +GO +~~START~~ +text +Query Text: EXEC babel_3592_proc_mixed_statements + Query Text: update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 + -> Update on babel_3592_t1 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: select/*+ nestloop(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ * from babel_3592_t1 inner join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 + -> Gather + Workers Planned: 3 + -> Nested Loop + -> Parallel Seq Scan on babel_3592_t1 + -> Index Scan using babel_3592_t2_pkey on babel_3592_t2 + Index Cond: (a2 = babel_3592_t1.a1) + Query Text: select/*+ mergejoin(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ * from babel_3592_t1 inner + join babel_3592_t2 + on babel_3592_t1.a1 = babel_3592_t2.a2 + -> Gather + Workers Planned: 1 + -> Merge Join + Merge Cond: (babel_3592_t1.a1 = babel_3592_t2.a2) + -> Parallel Index Scan using babel_3592_t1_pkey on babel_3592_t1 + -> Index Scan using babel_3592_t2_pkey on babel_3592_t2 + Query Text: update/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ babel_3592_t1 set a1 = 1 where b1 = 1 + -> Update on babel_3592_t1 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: delete/*+ mergejoin(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ babel_3592_t1 from babel_3592_t1 inner join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 where b1 = 1 and b2 = 1 + -> Delete on babel_3592_t1 + -> Merge Join + Merge Cond: (babel_3592_t1.a1 = babel_3592_t2.a2) + -> Sort + Sort Key: babel_3592_t1.a1 + -> Bitmap Heap Scan on babel_3592_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3592_t2.a2 + -> Bitmap Heap Scan on babel_3592_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3592_t2_b2babel_359155b730148d8fcf0167f32edb84e3f7d + Index Cond: (b2 = 1) + Query Text: delete/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) mergejoin(babel_3592_t1 babel_3592_t2) leading(babel_3592_t1 babel_3592_t2)*/ babel_3592_t1 from babel_3592_t1 left outer join babel_3592_t2 on babel_3592_t1.a1 = babel_3592_t2.a2 where b1 = 1 and b2 = 1 + -> Delete on babel_3592_t1 + -> Merge Join + Merge Cond: (babel_3592_t1.a1 = babel_3592_t2.a2) + -> Sort + Sort Key: babel_3592_t1.a1 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + -> Sort + Sort Key: babel_3592_t2.a2 + -> Bitmap Heap Scan on babel_3592_t2 + Recheck Cond: (b2 = 1) + -> Bitmap Index Scan on index_babel_3592_t2_b2babel_359155b730148d8fcf0167f32edb84e3f7d + Index Cond: (b2 = 1) + Query Text: insert +into +babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Bitmap Heap Scan on babel_3592_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: insert/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) */ into babel_3592_t2 select * from babel_3592_t1 where b1 = 1 + -> Insert on babel_3592_t2 + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + Query Text: update babel_3592_t1 set a1 = 1 where b1 = 1 + -> Update on babel_3592_t1 + -> Bitmap Heap Scan on babel_3592_t1 + Recheck Cond: (b1 = 1) + -> Bitmap Index Scan on index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 + Index Cond: (b1 = 1) + Query Text: select/*+ indexscan(babel_3592_t1 index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836) indexscan(babel_3592_t2 index_babel_3592_t2_b2babel_359155b730148d8fcf0167f32edb84e3f7d) */ * from babel_3592_t1 , babel_3592_t2 where b1 = 1 and b2 = 1 + -> Gather + Workers Planned: 1 + Single Copy: true + -> Nested Loop + -> Index Scan using index_babel_3592_t1_b1babel_35976c64b612d1f74e2768783beca3bf836 on babel_3592_t1 + Index Cond: (b1 = 1) + -> Materialize + -> Index Scan using index_babel_3592_t2_b2babel_359155b730148d8fcf0167f32edb84e3f7d on babel_3592_t2 + Index Cond: (b2 = 1) +~~END~~ + + +-- clean up +set babelfish_showplan_all off +go + +DROP PROCEDURE babel_3592_insert_multiline +GO + +DROP PROCEDURE babel_3592_insert_singleline +GO + +DROP PROCEDURE babel_3592_updates_multiline +GO + +DROP PROCEDURE babel_3592_updates_singleline +GO + +DROP PROCEDURE babel_3592_delete_multiline +GO + +DROP PROCEDURE babel_3592_delete_singleline +GO + +DROP PROCEDURE babel_3592_proc_mixed_statements +GO + +DROP TABLE babel_3592_t1 +GO + +DROP TABLE babel_3592_t2 +GO + +DROP TABLE babel_3592_t3 +GO diff --git a/test/JDBC/expected/parallel_query/BABEL-4294-vu-cleanup.out b/test/JDBC/expected/parallel_query/BABEL-4294-vu-cleanup.out new file mode 100644 index 0000000000..2e8e81d731 --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-4294-vu-cleanup.out @@ -0,0 +1,9 @@ + +-- Test to check if initialisation of Parallel Worker crash when babelfishpg_tsql.enable_pg_hint is set +drop table babel_4294_parallel_t1; +drop table babel_4294_parallel_t2; +drop table babel_4294_parallel_t3; +go + +drop table babel_4294_parallel_t4; +go diff --git a/test/JDBC/expected/parallel_query/BABEL-4294-vu-prepare.out b/test/JDBC/expected/parallel_query/BABEL-4294-vu-prepare.out new file mode 100644 index 0000000000..cad04efb9e --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-4294-vu-prepare.out @@ -0,0 +1,20 @@ + +-- Test to check if initialisation of Parallel Worker crash when babelfishpg_tsql.enable_pg_hint is set +create table babel_4294_parallel_t1(id INT, val int); +create table babel_4294_parallel_t2(babel_4294_parallel_t1_id INT, val int); +create table babel_4294_parallel_t3(babel_4294_parallel_t1_id INT, val int); +go + +insert into babel_4294_parallel_t1 values (1, 10), (2, 20), (3, 30); +insert into babel_4294_parallel_t2 values (1, 11), (2, 12), (3, 13); +insert into babel_4294_parallel_t3 values (1, 99), (2, 77), (3, 55); +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + + +create table babel_4294_parallel_t4(id INT, val int); +go diff --git a/test/JDBC/expected/parallel_query/BABEL-4294-vu-verify.out b/test/JDBC/expected/parallel_query/BABEL-4294-vu-verify.out new file mode 100644 index 0000000000..712a48e4aa --- /dev/null +++ b/test/JDBC/expected/parallel_query/BABEL-4294-vu-verify.out @@ -0,0 +1,56 @@ + +-- Test to check if initialisation of Parallel Worker crash when babelfishpg_tsql.enable_pg_hint is set +/* + * Set the enable_pg_hint, try to create parallel worker + */ +exec sp_babelfish_configure 'enable_pg_hint', 'on', 'server' +go + +select COUNT( babel_4294_t3.val), babel_4294_t2.val from babel_4294_t1 +inner join babel_4294_t2 on babel_4294_t1.id = babel_4294_t2.babel_4294_t1_id +inner join babel_4294_t3 on babel_4294_t1.id = babel_4294_t3.babel_4294_t1_id +GROUP BY babel_4294_t2.val +UNION ALL +select COUNT( babel_4294_t3.val), babel_4294_t2.val from babel_4294_t1 +inner join babel_4294_t2 on babel_4294_t1.id = babel_4294_t2.babel_4294_t1_id +inner join babel_4294_t3 on babel_4294_t1.id = babel_4294_t3.babel_4294_t1_id +GROUP BY babel_4294_t2.val +go +~~START~~ +int#!#int +1#!#11 +1#!#12 +1#!#13 +1#!#11 +1#!#12 +1#!#13 +~~END~~ + + +-- Used force parallel mode to create a parallel worker +select set_config('force_parallel_mode', '1', false) +go +~~START~~ +text +on +~~END~~ + + +-- to check if parallel worker generated for following query, will crash or not +select * from babel_4294_t4 +go +~~START~~ +int#!#int +~~END~~ + + +select set_config('force_parallel_mode', '0', false) +go +~~START~~ +text +off +~~END~~ + + +exec sp_babelfish_configure 'enable_pg_hint', 'off', 'server' +go 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/expected/pg_stat_statements_tsql.out b/test/JDBC/expected/pg_stat_statements_tsql.out new file mode 100644 index 0000000000..1ac3669a6a --- /dev/null +++ b/test/JDBC/expected/pg_stat_statements_tsql.out @@ -0,0 +1,658 @@ +-- psql +CREATE EXTENSION pg_stat_statements WITH SCHEMA sys; +go + +-- psql +ALTER SYSTEM SET pg_stat_statements.track = 'top'; +ALTER SYSTEM SET compute_query_id = 1; +SELECT pg_reload_conf(); +go +~~START~~ +bool +t +~~END~~ + + +SELECT pg_sleep(1); +go +~~START~~ +void + +~~END~~ + + +SELECT sys.pg_stat_statements_reset(); +go +~~START~~ +void + +~~END~~ + + +-- tsql +SELECT toplevel, query, calls, rows, plans from pg_stat_statements where queryid != 0 ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint#!#bigint +~~END~~ + + + +-- tsql +-- +-- simple and compound statements +-- +SELECT 1 AS "int"; +go +~~START~~ +int +1 +~~END~~ + + + +SELECT 'hello' + -- multiline + AS "text"; +go +~~START~~ +varchar +hello +~~END~~ + + +SELECT 'world' AS "text"; +go +~~START~~ +varchar +world +~~END~~ + + + +-- create/drop type +CREATE TYPE pgss_type from varchar(22) +go +DROP TYPE pgss_type +go + +-- transaction statements +BEGIN TRANSACTION; +SELECT 1 AS "int"; +SELECT 'hello' AS "text"; +COMMIT TRANSACTION; +go +~~START~~ +int +1 +~~END~~ + +~~START~~ +varchar +hello +~~END~~ + + +CREATE TABLE pgss_transaction(age int) +go +INSERT INTO pgss_transaction values(22),(12),(32),(21) +go +~~ROW COUNT: 4~~ + +BEGIN TRANSACTION; +INSERT INTO pgss_transaction values(12) +SAVE TRANSACTION insertstmt +select * from pgss_transaction +ROLLBACK TRANSACTION insertstmt +COMMIT +go +~~ROW COUNT: 1~~ + +~~START~~ +int +22 +12 +32 +21 +12 +~~END~~ + +DROP TABLE pgss_transaction +go + +-- cursor(T-SQL only statement, not visible in the view) +CREATE TABLE pgss_cursor(age int) +go +INSERT INTO pgss_cursor values(22),(12),(43) +go +~~ROW COUNT: 3~~ + +declare pgss_next cursor +for select * from pgss_cursor +open pgss_next +fetch next from pgss_next +go +~~START~~ +int +22 +~~END~~ + +DROP TABLE pgss_cursor +go + +-- break/continue/raiserror/print (These are T-SQL only statements, not visible in the view) +DECLARE @counter INT = 0; +WHILE @counter <= 5 +BEGIN +SET @counter = @counter + 1; +IF @counter = 4 +break +ELSE IF @counter = 2 +continue +ELSE +RAISERROR('Oops error', 1, 1) +PRINT @counter; +end +go + + +-- db statements +CREATE DATABASE pgss_db +go +DROP DATABASE pgss_db +go + +-- tsql +SELECT toplevel, query, calls, rows, plans from pg_stat_statements where queryid != 0 ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint#!#bigint +1#!#BEGIN TRANSACTION#!#2#!#0#!#0 +1#!#COMMIT#!#1#!#0#!#0 +1#!#COMMIT TRANSACTION#!#1#!#0#!#0 +1#!#CREATE DATABASE pgss_db#!#1#!#0#!#0 +1#!#CREATE TABLE pgss_cursor(age int)#!#1#!#0#!#0 +1#!#CREATE TABLE pgss_transaction(age int)#!#1#!#0#!#0 +1#!#CREATE TYPE pgss_type from varchar(22)#!#1#!#0#!#0 +1#!#DROP DATABASE pgss_db#!#1#!#0#!#0 +1#!#DROP TABLE pgss_cursor#!#1#!#0#!#0 +1#!#DROP TABLE pgss_transaction#!#1#!#0#!#0 +1#!#DROP TYPE pgss_type#!#1#!#0#!#0 +1#!#INSERT INTO pgss_cursor values($1),($2),($3)#!#1#!#3#!#0 +1#!#INSERT INTO pgss_transaction values($1)#!#1#!#1#!#0 +1#!#INSERT INTO pgss_transaction values($1),($2),($3),($4)#!#1#!#4#!#0 +1#!#ROLLBACK TRANSACTION insertstmt#!#1#!#0#!#0 +1#!#SAVE TRANSACTION insertstmt#!#1#!#0#!#0 +1#!#SELECT $1 -- multiline AS "text"#!#3#!#3#!#0 +1#!#SELECT $1 AS "int"#!#2#!#2#!#0 +1#!#SELECT toplevel, query, calls, rows, plans from pg_stat_statements where queryid != $1 ORDER BY query COLLATE "C"#!#1#!#0#!#0 +1#!#select * from pgss_cursor#!#1#!#1#!#0 +1#!#select * from pgss_transaction#!#1#!#5#!#0 +~~END~~ + + +-- psql +SELECT sys.pg_stat_statements_reset(); +go +~~START~~ +void + +~~END~~ + + +-- tsql +-- for information_schema.views the name in the view will be shown as information_schema_tsql.views +SELECT * FROM information_schema.views WHERE TABLE_NAME = 'india customers'; +go +~~START~~ +nvarchar#!#nvarchar#!#nvarchar#!#nvarchar#!#varchar#!#varchar +~~END~~ + + +SELECT toplevel, query, calls, rows, plans from pg_stat_statements where queryid != 0 ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint#!#bigint +1#!#SELECT * FROM information_schema_tsql.views WHERE TABLE_NAME = $1#!#1#!#0#!#0 +~~END~~ + + +-- psql +SELECT sys.pg_stat_statements_reset(); +go +~~START~~ +void + +~~END~~ + + +-- tsql +-- for create/drop/alter login internally we use sysadmin privileges to execute it. Query and queryid is not shown for any statement if user executing the query and owner of extension is not same. +CREATE LOGIN pgss_l1 with password = '12345678' +go +DROP LOGIN pgss_l1 +go + +SELECT toplevel, query from pg_stat_statements ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text +1#!# +1#!# +1#!# +~~END~~ + + +-- create insert alter select update delete trigger truncate on test table +CREATE TABLE pgss_test (a int, b char(20)); +go +ALTER TABLE pgss_test add c varchar(22) +go +SELECT * FROM pgss_test +go +~~START~~ +int#!#char#!#varchar +~~END~~ + +CREATE TRIGGER pgss_trigger1 on [dbo].[pgss_test] for insert as +PRINT 'after insert trigger called' +go + +INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa', 'bbb'); +go +~~WARNING (Code: 0)~~ + +~~WARNING (Message: after insert trigger called Server SQLState: S0001)~~ + +~~ROW COUNT: 10~~ + +UPDATE pgss_test SET b = 'bbb' WHERE a > 7; +DELETE FROM pgss_test WHERE a > 9; +go +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + +TRUNCATE TABLE pgss_test; +go + +-- role & permissions(grant revoke) +CREATE ROLE pgss_test_role +go +GRANT INSERT, UPDATE, SELECT ON pgss_test TO pgss_test_role +go +REVOKE INSERT, UPDATE, SELECT ON pgss_test FROM pgss_test_role +go + +-- enable/disable trigger +ALTER TABLE pgss_test ENABLE TRIGGER pgss_trigger1 +go +ALTER TABLE pgss_test DISABLE TRIGGER pgss_trigger1 +go + + +-- SELECT without constants +SELECT * FROM pgss_test ORDER BY a; +-- SELECT with IN clause +SELECT * FROM pgss_test WHERE a IN (1, 2, 3, 4, 5); +go +~~START~~ +int#!#char#!#varchar +~~END~~ + +~~START~~ +int#!#char#!#varchar +~~END~~ + + +SELECT toplevel, query, calls, rows, plans from pg_stat_statements where queryid != 0 and (query not like 'GRANT%' AND query not like 'REVOKE%') ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint#!#bigint +1#!#ALTER TABLE pgss_test DISABLE TRIGGER pgss_trigger1#!#1#!#0#!#0 +1#!#ALTER TABLE pgss_test ENABLE TRIGGER pgss_trigger1#!#1#!#0#!#0 +1#!#ALTER TABLE pgss_test add c varchar(22)#!#1#!#0#!#0 +1#!#CREATE ROLE pgss_test_role#!#1#!#0#!#0 +1#!#CREATE TABLE pgss_test (a int, b char(20))#!#1#!#0#!#0 +1#!#CREATE TRIGGER pgss_trigger1 on [dbo].[pgss_test] for insert asPRINT 'after insert trigger called'#!#1#!#0#!#0 +1#!#DELETE FROM pgss_test WHERE a > $1#!#1#!#1#!#0 +1#!#INSERT INTO pgss_test VALUES(generate_series($1, $2), $3, $4)#!#1#!#10#!#0 +1#!#SELECT * FROM pgss_test#!#1#!#0#!#0 +1#!#SELECT * FROM pgss_test ORDER BY a#!#1#!#0#!#0 +1#!#SELECT * FROM pgss_test WHERE a IN ($1, $2, $3, $4, $5)#!#1#!#0#!#0 +1#!#SELECT toplevel, query from pg_stat_statements ORDER BY query COLLATE "C"#!#1#!#3#!#0 +1#!#TRUNCATE TABLE pgss_test#!#1#!#0#!#0 +1#!#UPDATE pgss_test SET b = $1 WHERE a > $2#!#1#!#3#!#0 +~~END~~ + + +SELECT toplevel, query, rows, plans from pg_stat_statements where queryid != 0 and (query like 'GRANT%' OR query like 'REVOKE%') ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint +1#!#GRANT INSERT, UPDATE, SELECT ON pgss_test TO pgss_test_role#!#0#!#0 +1#!#REVOKE INSERT, UPDATE, SELECT ON pgss_test FROM pgss_test_role#!#0#!#0 +~~END~~ + + +-- psql +SELECT sys.pg_stat_statements_reset(); +go +~~START~~ +void + +~~END~~ + + +-- tsql +DROP TABLE pgss_test; +DROP ROLE pgss_test_role; +go + +-- group by rollup +SELECT a, b, c +FROM (VALUES (1, 2, 3), (4, NULL, 6), (7, 8, 9)) AS t (a, b, c) +GROUP BY ROLLUP(a, b), rollup(a, c) +ORDER BY a, b, c; +go +~~START~~ +int#!#int#!#int +#!##!# +1#!##!# +1#!##!# +1#!##!# +1#!##!#3 +1#!##!#3 +1#!#2#!# +1#!#2#!# +1#!#2#!#3 +4#!##!# +4#!##!# +4#!##!# +4#!##!# +4#!##!# +4#!##!#6 +4#!##!#6 +4#!##!#6 +7#!##!# +7#!##!# +7#!##!# +7#!##!#9 +7#!##!#9 +7#!#8#!# +7#!#8#!# +7#!#8#!#9 +~~END~~ + + +SELECT COUNT(*) FROM pg_stat_statements WHERE query LIKE '%GROUP BY%ROLLUP%'; +go +~~START~~ +int +1 +~~END~~ + + +-- psql +SELECT sys.pg_stat_statements_reset(); +go +~~START~~ +void + +~~END~~ + + +-- tsql + +-- +-- insert, update, delete on test table to validate WAL generation metrics +-- +CREATE TABLE pgss_test (a int, b char(20)); +INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa'); +UPDATE pgss_test SET b = 'bbb' WHERE a > 7; +DELETE FROM pgss_test WHERE a > 9; +-- DROP test table +DROP TABLE pgss_test; +go +~~ROW COUNT: 10~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- Check WAL is generated for the above statements +SELECT query, calls, rows +FROM pg_stat_statements where wal_bytes != 0 and wal_records != 0 ORDER BY query COLLATE "C"; +go +~~START~~ +text#!#bigint#!#bigint +CREATE TABLE pgss_test (a int, b char(20))#!#1#!#0 +DELETE FROM pgss_test WHERE a > $1#!#1#!#1 +DROP TABLE pgss_test#!#1#!#0 +INSERT INTO pgss_test VALUES(generate_series($1, $2), $3)#!#1#!#10 +UPDATE pgss_test SET b = $1 WHERE a > $2#!#1#!#3 +~~END~~ + + +-- tsql + +-- +-- insert, update, delete on test table to validate time generation metrics +-- +CREATE TABLE pgss_test (a int, b char(20)); +INSERT INTO pgss_test VALUES(generate_series(1, 10), 'aaa'); +UPDATE pgss_test SET b = 'bbb' WHERE a > 7; +DELETE FROM pgss_test WHERE a > 9; +-- DROP test table +DROP TABLE pgss_test; +go +~~ROW COUNT: 10~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 1~~ + + +-- Check Time related columns is generated for the above statements +SELECT query, calls, rows +FROM pg_stat_statements where total_exec_time > 0 and min_exec_time > 0 ORDER BY query COLLATE "C"; +go +~~START~~ +text#!#bigint#!#bigint +#!#1#!#1 +CREATE TABLE pgss_test (a int, b char(20))#!#2#!#0 +DELETE FROM pgss_test WHERE a > $1#!#1#!#1 +DELETE FROM pgss_test WHERE a > $1#!#1#!#1 +DROP TABLE pgss_test#!#2#!#0 +INSERT INTO pgss_test VALUES(generate_series($1, $2), $3)#!#1#!#10 +INSERT INTO pgss_test VALUES(generate_series($1, $2), $3)#!#1#!#10 +SELECT query, calls, rowsFROM pg_stat_statements where wal_bytes != $1 and wal_records != $2 ORDER BY query COLLATE "C"#!#1#!#5 +UPDATE pgss_test SET b = $1 WHERE a > $2#!#1#!#3 +UPDATE pgss_test SET b = $1 WHERE a > $2#!#1#!#3 +~~END~~ + + +-- tsql +-- join, aggregate functions, view, constraints +CREATE TABLE pgss_cust(customerid int not null, name varchar(22), age int, check (age>=18), primary key(customerid)) +CREATE TABLE pgss_orders(orderid int not null, customerid int, country varchar(20) default 'INDIA', primary key(orderid), foreign key(customerid) references pgss_cust(customerid)) +INSERT INTO pgss_cust values(1, 'ABC', 18),(2,'XYZ', 21), (3, 'LMN', 29),(4, 'PQR', 52),(5, 'STU', 23) +INSERT INTO pgss_orders values(10, 5, 'London'), (11, 3, 'India'), (12, 2, 'USA'), (13, 4, 'Pakistan'),(14, 5, 'Germany'),(15, 1, 'India') +go +~~ROW COUNT: 5~~ + +~~ROW COUNT: 6~~ + + +SELECT pgss_cust.name, pgss_orders.orderid, pgss_orders.country from pgss_orders inner join pgss_cust on pgss_cust.customerid = pgss_orders.customerid; +go +~~START~~ +varchar#!#int#!#varchar +STU#!#10#!#London +LMN#!#11#!#India +XYZ#!#12#!#USA +PQR#!#13#!#Pakistan +STU#!#14#!#Germany +ABC#!#15#!#India +~~END~~ + + +SELECT COUNT(*) from pgss_orders where country ='India' +go +~~START~~ +int +2 +~~END~~ + + +CREATE VIEW [India customers] as select customerid from pgss_orders where country = 'India' +go + +SELECT * FROM [India customers] +go +~~START~~ +int +3 +1 +~~END~~ + + +SELECT * FROM pgss_cust +go +~~START~~ +int#!#varchar#!#int +1#!#ABC#!#18 +2#!#XYZ#!#21 +3#!#LMN#!#29 +4#!#PQR#!#52 +5#!#STU#!#23 +~~END~~ + + +SELECT AVG(age) FROM pgss_cust +go +~~START~~ +int +28 +~~END~~ + + +SELECT REVERSE(name) FROM pgss_cust +go +~~START~~ +text +CBA +ZYX +NML +RQP +UTS +~~END~~ + + +-- tsql function +CREATE FUNCTION pgss_f1(@a INT) RETURNS INT AS BEGIN RETURN (@a + 1) END; +go + +CREATE SEQUENCE [dbo].[newCounter] AS int START WITH 5 increment by 5 +go + +-- this will show up as select nextval() in the view +SELECT NEXT VALUE FOR [dbo].[newCounter] +go +~~START~~ +bigint +5 +~~END~~ + + +DROP SEQUENCE [dbo].[newCounter] +go + +-- Inline table-valued function +CREATE FUNCTION [dbo].[getCustomers](@age int) returns table as return +(select pgss_cust.customerid, pgss_cust.name, pgss_cust.age from pgss_cust +where age >= @age) +go +SELECT * FROM [dbo].[getCustomers](20) +go +~~START~~ +int#!#varchar#!#int +2#!#XYZ#!#21 +3#!#LMN#!#29 +4#!#PQR#!#52 +5#!#STU#!#23 +~~END~~ + + +-- Temp table +CREATE TABLE #pgss_demo(age int) +go + +-- tsql procedure +CREATE PROC pgss_p1 @a INT, @b FLOAT AS SELECT @a, @b; +go + + +DROP VIEW [India customers] +go +DROP TABLE pgss_orders +go +DROP TABLE pgss_cust +go +DROP FUNCTION [dbo].[getCustomers] +go +DROP FUNCTION pgss_f1 +go +DROP PROCEDURE pgss_p1; +go + + +-- tsql +SELECT toplevel, query, calls, rows, plans from pg_stat_statements where queryid != 0 ORDER BY query COLLATE "C"; +go +~~START~~ +bit#!#text#!#bigint#!#bigint#!#bigint +1#!#CREATE FUNCTION [dbo].[getCustomers](@age int) returns table as return (select pgss_cust.customerid, pgss_cust.name, pgss_cust.age from pgss_custwhere age >= @age)#!#1#!#0#!#0 +1#!#CREATE FUNCTION pgss_f1(@a INT) RETURNS INT AS BEGIN RETURN (@a + 1) END;#!#1#!#0#!#0 +1#!#CREATE PROC pgss_p1 @a INT, @b FLOAT AS SELECT @a, @b;#!#1#!#0#!#0 +1#!#CREATE SEQUENCE [dbo].[newCounter] AS int START WITH 5 increment by 5#!#1#!#0#!#0 +1#!#CREATE TABLE #pgss_demo(age int)#!#1#!#0#!#0 +1#!#CREATE TABLE pgss_cust(customerid int not null, name varchar(22), age int, check (age>=18), primary key(customerid))#!#1#!#0#!#0 +1#!#CREATE TABLE pgss_orders(orderid int not null, customerid int, country varchar(20) default 'INDIA', primary key(orderid), foreign key(customerid) references pgss_cust(customerid))#!#1#!#0#!#0 +1#!#CREATE TABLE pgss_test (a int, b char(20))#!#2#!#0#!#0 +1#!#CREATE VIEW [India customers] as select customerid from pgss_orders where country = 'India'#!#1#!#0#!#0 +1#!#DELETE FROM pgss_test WHERE a > $1#!#1#!#1#!#0 +1#!#DELETE FROM pgss_test WHERE a > $1#!#1#!#1#!#0 +1#!#DROP FUNCTION [dbo].[getCustomers]#!#1#!#0#!#0 +1#!#DROP FUNCTION pgss_f1#!#1#!#0#!#0 +1#!#DROP PROCEDURE pgss_p1#!#1#!#0#!#0 +1#!#DROP SEQUENCE [dbo].[newCounter]#!#1#!#0#!#0 +1#!#DROP TABLE pgss_cust#!#1#!#0#!#0 +1#!#DROP TABLE pgss_orders#!#1#!#0#!#0 +1#!#DROP TABLE pgss_test#!#2#!#0#!#0 +1#!#DROP VIEW [India customers]#!#1#!#0#!#0 +1#!#INSERT INTO pgss_cust values($1, $2, $3),($4,$5, $6), ($7, $8, $9),($10, $11, $12),($13, $14, $15)#!#1#!#5#!#0 +1#!#INSERT INTO pgss_orders values($1, $2, $3), ($4, $5, $6), ($7, $8, $9), ($10, $11, $12),($13, $14, $15),($16, $17, $18)#!#1#!#6#!#0 +1#!#INSERT INTO pgss_test VALUES(generate_series($1, $2), $3)#!#1#!#10#!#0 +1#!#INSERT INTO pgss_test VALUES(generate_series($1, $2), $3)#!#1#!#10#!#0 +1#!#SELECT nextval($1)#!#1#!#1#!#0 +1#!#SELECT * FROM [India customers]#!#1#!#2#!#0 +1#!#SELECT * FROM [dbo].[getCustomers]($1)#!#1#!#4#!#0 +1#!#SELECT * FROM pgss_cust#!#1#!#5#!#0 +1#!#SELECT AVG(age) FROM pgss_cust#!#1#!#1#!#0 +1#!#SELECT COUNT(*) from pgss_orders where country =$1#!#1#!#1#!#0 +1#!#SELECT REVERSE(name) FROM pgss_cust#!#1#!#5#!#0 +1#!#SELECT pgss_cust.name, pgss_orders.orderid, pgss_orders.country from pgss_orders inner join pgss_cust on pgss_cust.customerid = pgss_orders.customerid#!#1#!#6#!#0 +1#!#SELECT query, calls, rowsFROM pg_stat_statements where total_exec_time > $1 and min_exec_time > $2 ORDER BY query COLLATE "C"#!#1#!#10#!#0 +1#!#SELECT query, calls, rowsFROM pg_stat_statements where wal_bytes != $1 and wal_records != $2 ORDER BY query COLLATE "C"#!#1#!#5#!#0 +1#!#UPDATE pgss_test SET b = $1 WHERE a > $2#!#1#!#3#!#0 +1#!#UPDATE pgss_test SET b = $1 WHERE a > $2#!#1#!#3#!#0 +~~END~~ + + +-- psql +DROP EXTENSION pg_stat_statements; +go + + diff --git a/test/JDBC/expected/pgr_000_test_setup.out b/test/JDBC/expected/pgr_000_test_setup.out new file mode 100644 index 0000000000..92a1838aa7 --- /dev/null +++ b/test/JDBC/expected/pgr_000_test_setup.out @@ -0,0 +1,439 @@ + + + + + + +-- tsql +-- \getenv libdir PG_LIBDIR +-- GO +-- \getenv dlsuffix PG_DLSUFFIX +-- GO +-- \set regresslib :libdir '/regress' :dlsuffix +-- GO +CREATE TABLE CHAR_TBL(f1 char(4)); +GO + +INSERT INTO CHAR_TBL (f1) VALUES + ('a'), + ('ab'), + ('abcd'), + ('abcd '); +GO +~~ROW COUNT: 4~~ + + +-- psql +VACUUM master_dbo.CHAR_TBL; +GO + +-- tsql +CREATE TABLE FLOAT8_TBL(f1 float); +GO + +INSERT INTO FLOAT8_TBL(f1) VALUES + ('0.0'), + ('-34.84'), + ('-1004.30'), + ('-1.2345678901234e+200'), + ('-1.2345678901234e-200'); +GO +~~ROW COUNT: 5~~ + + +-- psql +VACUUM master_dbo.FLOAT8_TBL; +GO + +-- tsql +CREATE TABLE INT2_TBL(f1 int2); +GO + +INSERT INTO INT2_TBL(f1) VALUES + ('0 '), + (' 1234 '), + (' -1234'), + ('32767'), -- largest and smallest values + ('-32767'); +GO +~~ROW COUNT: 5~~ + + +-- psql +VACUUM master_dbo.INT2_TBL; +GO + +-- tsql +CREATE TABLE INT4_TBL(f1 int); +GO + +INSERT INTO INT4_TBL(f1) VALUES + (' 0 '), + ('123456 '), + (' -123456'), + ('2147483647'), -- largest and smallest values + ('-2147483647'); +GO +~~ROW COUNT: 5~~ + + +-- psql +VACUUM master_dbo.INT4_TBL; +GO + +-- tsql +CREATE TABLE INT8_TBL(q1 bigint, q2 bigint); +GO + +INSERT INTO INT8_TBL VALUES + (' 123 ',' 456'), + ('123 ','4567890123456789'), + ('4567890123456789','123'), + ('+4567890123456789','4567890123456789'), + ('+4567890123456789','-4567890123456789'); +GO +~~ROW COUNT: 5~~ + + +-- psql +VACUUM master_dbo.INT8_TBL; +GO + +-- tsql +CREATE TABLE POINT_TBL(f1 point); +GO + +INSERT INTO POINT_TBL(f1) VALUES + ('(0.0,0.0)'), + ('(-10.0,0.0)'), + ('(-3.0,4.0)'), + ('(5.1, 34.5)'), + ('(-5.0,-12.0)'), + ('(1e-300,-1e-300)'), -- To underflow + ('(1e+300,Inf)'), -- To overflow + ('(Inf,1e+300)'), -- Transposed + (' ( Nan , NaN ) '), + ('10.0,10.0'); +GO +~~ROW COUNT: 10~~ + + +-- We intentionally don't vacuum point_tbl here; geometry depends on that +CREATE TABLE TEXT_TBL (f1 varchar(max)); +GO + +INSERT INTO TEXT_TBL VALUES + ('doh!'), + ('hi de ho neighbor'); +GO +~~ROW COUNT: 2~~ + + +-- psql +VACUUM master_dbo.TEXT_TBL; +GO + +-- tsql +CREATE TABLE VARCHAR_TBL(f1 varchar(4)); +GO + + +INSERT INTO VARCHAR_TBL (f1) VALUES + ('a'), + ('ab'), + ('abcd'), + ('abcd '); +GO +~~ROW COUNT: 4~~ + + +-- psql +VACUUM master_dbo.VARCHAR_TBL; +GO + +-- tsql +CREATE TABLE onek ( + unique1 int, + unique2 int, + two int, + four int, + ten int, + twenty int, + hundred int, + thousand int, + twothousand int, + fivethous int, + tenthous int, + odd int, + even int, + stringu1 name, + stringu2 name, + string4 name +); +GO + +-- bash +/bin/bash input/pg_regress/load_onek.sh + +-----copy onek table from /data/onek.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/onek.data' +COPY master_dbo.onek FROM :'filename'; +COPY 1000 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.onek; +GO + +-- tsql +CREATE TABLE onek2 ( + unique1 int, + unique2 int, + two int, + four int, + ten int, + twenty int, + hundred int, + thousand int, + twothousand int, + fivethous int, + tenthous int, + odd int, + even int, + stringu1 name, + stringu2 name, + string4 name +); +GO + +insert into onek2 select * from onek; +GO +~~ROW COUNT: 1000~~ + + +-- psql +VACUUM ANALYZE master_dbo.onek2; +GO + +-- tsql +CREATE TABLE tenk1 ( + unique1 int, + unique2 int, + two int, + four int, + ten int, + twenty int, + hundred int, + thousand int, + twothousand int, + fivethous int, + tenthous int, + odd int, + even int, + stringu1 name, + stringu2 name, + string4 name +); +GO + +-- bash +/bin/bash input/pg_regress/load_tenk.sh + +-----copy tenk1 table from /data/tenk.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/tenk.data' +COPY master_dbo.tenk1 FROM :'filename'; +COPY 10000 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.tenk1; +GO + +-- tsql +CREATE TABLE tenk2 ( + unique1 int, + unique2 int, + two int, + four int, + ten int, + twenty int, + hundred int, + thousand int, + twothousand int, + fivethous int, + tenthous int, + odd int, + even int, + stringu1 name, + stringu2 name, + string4 name +); +GO + +insert into tenk2 select * from tenk1; +GO +~~ROW COUNT: 10000~~ + + +-- psql +VACUUM ANALYZE master_dbo.tenk2; +GO + +-- tsql +CREATE TABLE person ( + name varchar(max), + age int, + location point +); +GO + +-- bash +/bin/bash input/pg_regress/load_person.sh + +-----copy person table from /data/person.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/person.data' +COPY master_dbo.person FROM :'filename'; +COPY 50 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.person; +GO + +-- tsql +CREATE TABLE emp ( + name varchar(max), + age int, + location point, + salary int, + manager name +) +GO + +-- bash +/bin/bash input/pg_regress/load_emp.sh + +-----copy emp table from /data/emp.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/emp.data' +COPY master_dbo.emp FROM :'filename'; +COPY 3 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.emp; +GO + +-- tsql +CREATE TABLE student ( + name varchar(max), + age int, + location point, + gpa float +); +GO + +-- bash +/bin/bash input/pg_regress/load_student.sh + +-----copy student table from /data/student.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/student.data' +COPY master_dbo.student FROM :'filename'; +COPY 2 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.student; +GO + +-- tsql + +CREATE TABLE stud_emp ( + name varchar(max), + age int, + location point, + salary int, + manager name, + gpa float, + [percent] int +) ; +GO + +-- bash +/bin/bash input/pg_regress/load_stud_emp.sh + +-----copy stud_emp table from /data/stud_emp.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/stud_emp.data' +COPY master_dbo.stud_emp FROM :'filename'; +COPY 3 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.stud_emp; +GO + +-- tsql +CREATE TABLE aggtest ( + a int, + b float +); +GO + +-- bash +/bin/bash input/pg_regress/load_aggtest.sh + +-----copy aggtest table from /data/agg.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/agg.data' +COPY master_dbo.aggtest FROM :'filename'; +COPY 4 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.aggtest; +GO + +-- tsql +CREATE TABLE road ( + name varchar(max), + thepath path +); +GO + +-- bash +/bin/bash input/pg_regress/load_road.sh + +-----copy road table from /data/streets.data----- +\getenv pg_src PG_SRC +\set filename :pg_src '/src/test/regress/data/streets.data' +COPY master_dbo.road FROM :'filename'; +COPY 5124 +----- done ----- + +-- psql +VACUUM ANALYZE master_dbo.road; +GO + + + + + + + + + + + + + + + + + + + diff --git a/test/JDBC/expected/pgr_delete.out b/test/JDBC/expected/pgr_delete.out new file mode 100644 index 0000000000..701e5fa094 --- /dev/null +++ b/test/JDBC/expected/pgr_delete.out @@ -0,0 +1,60 @@ +CREATE TABLE delete_test ( + id SERIAL PRIMARY KEY, + a INT, + b text +); +GO + +INSERT INTO delete_test (a) VALUES (10); +GO +~~ROW COUNT: 1~~ + +INSERT INTO delete_test (a, b) VALUES (50, repeat('x', 10000)); +GO +~~ROW COUNT: 1~~ + +INSERT INTO delete_test (a) VALUES (100); +GO +~~ROW COUNT: 1~~ + + +-- allow an alias to be specified for DELETE's target table +DELETE dt FROM delete_test dt WHERE dt.a > 75; +GO +~~ROW COUNT: 1~~ + + +-- if an alias is specified, don't allow the original table name +-- to be referenced +DELETE dt FROM delete_test dt WHERE delete_test.a > 25; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid reference to FROM-clause entry for table "delete_test")~~ + + +SELECT id, a, char_length(b) FROM delete_test; +GO +~~START~~ +int#!#int#!#int +1#!#10#!# +2#!#50#!#10000 +~~END~~ + + +-- delete a row with a TOASTed value +DELETE FROM delete_test WHERE a > 25; +GO +~~ROW COUNT: 1~~ + + +SELECT id, a, char_length(b) FROM delete_test; +GO +~~START~~ +int#!#int#!#int +1#!#10#!# +~~END~~ + + +DROP TABLE delete_test; +GO diff --git a/test/JDBC/expected/pgr_select.out b/test/JDBC/expected/pgr_select.out new file mode 100644 index 0000000000..f6c258c9a9 --- /dev/null +++ b/test/JDBC/expected/pgr_select.out @@ -0,0 +1,1025 @@ + +-- +-- SELECT +-- +-- btree index +-- awk '{if($1<10){print;}else{next;}}' onek.data | sort +0n -1 +-- +SELECT * FROM onek + WHERE onek.unique1 < 10 + ORDER BY onek.unique1; +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#varchar#!#varchar#!#varchar +0#!#998#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#1#!#AAAAAA#!#KMBAAA#!#OOOOxx +1#!#214#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#2#!#3#!#BAAAAA#!#GIAAAA#!#OOOOxx +2#!#326#!#0#!#2#!#2#!#2#!#2#!#2#!#2#!#2#!#2#!#4#!#5#!#CAAAAA#!#OMAAAA#!#OOOOxx +3#!#431#!#1#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#6#!#7#!#DAAAAA#!#PQAAAA#!#VVVVxx +4#!#833#!#0#!#0#!#4#!#4#!#4#!#4#!#4#!#4#!#4#!#8#!#9#!#EAAAAA#!#BGBAAA#!#HHHHxx +5#!#541#!#1#!#1#!#5#!#5#!#5#!#5#!#5#!#5#!#5#!#10#!#11#!#FAAAAA#!#VUAAAA#!#HHHHxx +6#!#978#!#0#!#2#!#6#!#6#!#6#!#6#!#6#!#6#!#6#!#12#!#13#!#GAAAAA#!#QLBAAA#!#OOOOxx +7#!#647#!#1#!#3#!#7#!#7#!#7#!#7#!#7#!#7#!#7#!#14#!#15#!#HAAAAA#!#XYAAAA#!#VVVVxx +8#!#653#!#0#!#0#!#8#!#8#!#8#!#8#!#8#!#8#!#8#!#16#!#17#!#IAAAAA#!#DZAAAA#!#HHHHxx +9#!#49#!#1#!#1#!#9#!#9#!#9#!#9#!#9#!#9#!#9#!#18#!#19#!#JAAAAA#!#XBAAAA#!#HHHHxx +~~END~~ + + +-- +-- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 +-- +SELECT onek.unique1, onek.stringu1 FROM onek + WHERE onek.unique1 < 20 + ORDER BY unique1 desc; +GO +~~START~~ +int#!#varchar +19#!#TAAAAA +18#!#SAAAAA +17#!#RAAAAA +16#!#QAAAAA +15#!#PAAAAA +14#!#OAAAAA +13#!#NAAAAA +12#!#MAAAAA +11#!#LAAAAA +10#!#KAAAAA +9#!#JAAAAA +8#!#IAAAAA +7#!#HAAAAA +6#!#GAAAAA +5#!#FAAAAA +4#!#EAAAAA +3#!#DAAAAA +2#!#CAAAAA +1#!#BAAAAA +0#!#AAAAAA +~~END~~ + + +-- +-- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 +-- +SELECT onek.unique1, onek.stringu1 FROM onek + WHERE onek.unique1 > 980 + ORDER BY stringu1 asc; +GO +~~START~~ +int#!#varchar +988#!#AMAAAA +989#!#BMAAAA +990#!#CMAAAA +991#!#DMAAAA +992#!#EMAAAA +993#!#FMAAAA +994#!#GMAAAA +995#!#HMAAAA +996#!#IMAAAA +997#!#JMAAAA +998#!#KMAAAA +999#!#LMAAAA +981#!#TLAAAA +982#!#ULAAAA +983#!#VLAAAA +984#!#WLAAAA +985#!#XLAAAA +986#!#YLAAAA +987#!#ZLAAAA +~~END~~ + + +-- +-- awk '{if($1>980){print $1,$16;}else{next;}}' onek.data | +-- sort +1d -2 +0nr -1 +-- +SELECT onek.unique1, onek.string4 FROM onek + WHERE onek.unique1 > 980 + ORDER BY string4 asc, unique1 desc; +GO +~~START~~ +int#!#varchar +999#!#AAAAxx +995#!#AAAAxx +983#!#AAAAxx +982#!#AAAAxx +981#!#AAAAxx +998#!#HHHHxx +997#!#HHHHxx +993#!#HHHHxx +990#!#HHHHxx +986#!#HHHHxx +996#!#OOOOxx +991#!#OOOOxx +988#!#OOOOxx +987#!#OOOOxx +985#!#OOOOxx +994#!#VVVVxx +992#!#VVVVxx +989#!#VVVVxx +984#!#VVVVxx +~~END~~ + + +-- +-- awk '{if($1>980){print $1,$16;}else{next;}}' onek.data | +-- sort +1dr -2 +0n -1 +-- +SELECT onek.unique1, onek.string4 FROM onek + WHERE onek.unique1 > 980 + ORDER BY string4 desc, unique1 asc; +GO +~~START~~ +int#!#varchar +984#!#VVVVxx +989#!#VVVVxx +992#!#VVVVxx +994#!#VVVVxx +985#!#OOOOxx +987#!#OOOOxx +988#!#OOOOxx +991#!#OOOOxx +996#!#OOOOxx +986#!#HHHHxx +990#!#HHHHxx +993#!#HHHHxx +997#!#HHHHxx +998#!#HHHHxx +981#!#AAAAxx +982#!#AAAAxx +983#!#AAAAxx +995#!#AAAAxx +999#!#AAAAxx +~~END~~ + + +-- +-- awk '{if($1<20){print $1,$16;}else{next;}}' onek.data | +-- sort +0nr -1 +1d -2 +-- +SELECT onek.unique1, onek.string4 FROM onek + WHERE onek.unique1 < 20 + ORDER BY unique1 desc, string4 asc; +GO +~~START~~ +int#!#varchar +19#!#OOOOxx +18#!#VVVVxx +17#!#HHHHxx +16#!#OOOOxx +15#!#VVVVxx +14#!#AAAAxx +13#!#OOOOxx +12#!#AAAAxx +11#!#OOOOxx +10#!#AAAAxx +9#!#HHHHxx +8#!#HHHHxx +7#!#VVVVxx +6#!#OOOOxx +5#!#HHHHxx +4#!#HHHHxx +3#!#VVVVxx +2#!#OOOOxx +1#!#OOOOxx +0#!#OOOOxx +~~END~~ + + +-- +-- awk '{if($1<20){print $1,$16;}else{next;}}' onek.data | +-- sort +0n -1 +1dr -2 +-- +SELECT onek.unique1, onek.string4 FROM onek + WHERE onek.unique1 < 20 + ORDER BY unique1 asc, string4 desc; +GO +~~START~~ +int#!#varchar +0#!#OOOOxx +1#!#OOOOxx +2#!#OOOOxx +3#!#VVVVxx +4#!#HHHHxx +5#!#HHHHxx +6#!#OOOOxx +7#!#VVVVxx +8#!#HHHHxx +9#!#HHHHxx +10#!#AAAAxx +11#!#OOOOxx +12#!#AAAAxx +13#!#OOOOxx +14#!#AAAAxx +15#!#VVVVxx +16#!#OOOOxx +17#!#HHHHxx +18#!#VVVVxx +19#!#OOOOxx +~~END~~ + + +-- psql +-- +-- test partial btree indexes +-- +-- As of 7.2, planner probably won't pick an indexscan without stats, +-- so ANALYZE first. Also, we want to prevent it from picking a bitmapscan +-- followed by sort, because that could hide index ordering problems. +-- +ANALYZE master_dbo.onek2; +GO + +-- tsql +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('enable_sort', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +-- +-- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 +-- +-- ORDER IS DIFFERENT compared with orginal regression test +SELECT onek2.* FROM onek2 WHERE onek2.unique1 < 10; +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#int#!#varchar#!#varchar#!#varchar +9#!#49#!#1#!#1#!#9#!#9#!#9#!#9#!#9#!#9#!#9#!#18#!#19#!#JAAAAA#!#XBAAAA#!#HHHHxx +1#!#214#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#2#!#3#!#BAAAAA#!#GIAAAA#!#OOOOxx +2#!#326#!#0#!#2#!#2#!#2#!#2#!#2#!#2#!#2#!#2#!#4#!#5#!#CAAAAA#!#OMAAAA#!#OOOOxx +3#!#431#!#1#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#3#!#6#!#7#!#DAAAAA#!#PQAAAA#!#VVVVxx +5#!#541#!#1#!#1#!#5#!#5#!#5#!#5#!#5#!#5#!#5#!#10#!#11#!#FAAAAA#!#VUAAAA#!#HHHHxx +7#!#647#!#1#!#3#!#7#!#7#!#7#!#7#!#7#!#7#!#7#!#14#!#15#!#HAAAAA#!#XYAAAA#!#VVVVxx +8#!#653#!#0#!#0#!#8#!#8#!#8#!#8#!#8#!#8#!#8#!#16#!#17#!#IAAAAA#!#DZAAAA#!#HHHHxx +4#!#833#!#0#!#0#!#4#!#4#!#4#!#4#!#4#!#4#!#4#!#8#!#9#!#EAAAAA#!#BGBAAA#!#HHHHxx +6#!#978#!#0#!#2#!#6#!#6#!#6#!#6#!#6#!#6#!#6#!#12#!#13#!#GAAAAA#!#QLBAAA#!#OOOOxx +0#!#998#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#0#!#1#!#AAAAAA#!#KMBAAA#!#OOOOxx +~~END~~ + + +-- +-- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 +-- +SELECT onek2.unique1, onek2.stringu1 FROM onek2 + WHERE onek2.unique1 < 20 + ORDER BY unique1 desc; +GO +~~START~~ +int#!#varchar +19#!#TAAAAA +18#!#SAAAAA +17#!#RAAAAA +16#!#QAAAAA +15#!#PAAAAA +14#!#OAAAAA +13#!#NAAAAA +12#!#MAAAAA +11#!#LAAAAA +10#!#KAAAAA +9#!#JAAAAA +8#!#IAAAAA +7#!#HAAAAA +6#!#GAAAAA +5#!#FAAAAA +4#!#EAAAAA +3#!#DAAAAA +2#!#CAAAAA +1#!#BAAAAA +0#!#AAAAAA +~~END~~ + + +-- +-- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 +-- +-- ORDER IS DIFFERENT compared with orginal regression test +SELECT onek2.unique1, onek2.stringu1 FROM onek2 + WHERE onek2.unique1 > 980; +GO +~~START~~ +int#!#varchar +997#!#JMAAAA +995#!#HMAAAA +999#!#LMAAAA +983#!#VLAAAA +989#!#BMAAAA +986#!#YLAAAA +996#!#IMAAAA +982#!#ULAAAA +992#!#EMAAAA +990#!#CMAAAA +991#!#DMAAAA +984#!#WLAAAA +981#!#TLAAAA +998#!#KMAAAA +993#!#FMAAAA +994#!#GMAAAA +988#!#AMAAAA +987#!#ZLAAAA +985#!#XLAAAA +~~END~~ + + +-- RESET enable_seqscan; +-- RESET enable_bitmapscan; +-- RESET enable_sort; +select set_config('enable_seqscan', 'on', false); +GO +~~START~~ +text +on +~~END~~ + +select set_config('enable_bitmapscan', 'on', false); +GO +~~START~~ +text +on +~~END~~ + +select set_config('enable_sort', 'on', false); +GO +~~START~~ +text +on +~~END~~ + + +-- psql +-- +-- awk '{print $1,$2;}' person.data | +-- awk '{if(NF!=2){print $3,$2;}else{print;}}' - emp.data | +-- awk '{if(NF!=2){print $3,$2;}else{print;}}' - student.data | +-- awk 'BEGIN{FS=" ";}{if(NF!=2){print $4,$5;}else{print;}}' - stud_emp.data +-- +-- SELECT name, age FROM person*; ??? check if different +-- MISSING LAST 8 ROWS compared with orginal regression test +SELECT p.name, p.age FROM master_dbo.person* p; +GO +~~START~~ +"sys"."varchar"#!#int4 +mike#!#40 +joe#!#20 +sally#!#34 +sandra#!#19 +alex#!#30 +sue#!#50 +denise#!#24 +sarah#!#88 +teresa#!#38 +nan#!#28 +leah#!#68 +wendy#!#78 +melissa#!#28 +joan#!#18 +mary#!#8 +jane#!#58 +liza#!#38 +jean#!#28 +jenifer#!#38 +juanita#!#58 +susan#!#78 +zena#!#98 +martie#!#88 +chris#!#78 +pat#!#18 +zola#!#58 +louise#!#98 +edna#!#18 +bertha#!#88 +sumi#!#38 +koko#!#88 +gina#!#18 +rean#!#48 +sharon#!#78 +paula#!#68 +julie#!#68 +belinda#!#38 +karen#!#48 +carina#!#58 +diane#!#18 +esther#!#98 +trudy#!#88 +fanny#!#8 +carmen#!#78 +lita#!#25 +pamela#!#48 +sandy#!#38 +trisha#!#88 +uma#!#78 +velma#!#68 +~~END~~ + + +-- +-- awk '{print $1,$2;}' person.data | +-- awk '{if(NF!=2){print $3,$2;}else{print;}}' - emp.data | +-- awk '{if(NF!=2){print $3,$2;}else{print;}}' - student.data | +-- awk 'BEGIN{FS=" ";}{if(NF!=1){print $4,$5;}else{print;}}' - stud_emp.data | +-- sort +1nr -2 +-- +SELECT p.name, p.age FROM master_dbo.person* p ORDER BY age desc, name; +GO +~~START~~ +"sys"."varchar"#!#int4 +esther#!#98 +louise#!#98 +zena#!#98 +bertha#!#88 +koko#!#88 +martie#!#88 +sarah#!#88 +trisha#!#88 +trudy#!#88 +carmen#!#78 +chris#!#78 +sharon#!#78 +susan#!#78 +uma#!#78 +wendy#!#78 +julie#!#68 +leah#!#68 +paula#!#68 +velma#!#68 +carina#!#58 +jane#!#58 +juanita#!#58 +zola#!#58 +sue#!#50 +karen#!#48 +pamela#!#48 +rean#!#48 +mike#!#40 +belinda#!#38 +jenifer#!#38 +liza#!#38 +sandy#!#38 +sumi#!#38 +teresa#!#38 +sally#!#34 +alex#!#30 +jean#!#28 +melissa#!#28 +nan#!#28 +lita#!#25 +denise#!#24 +joe#!#20 +sandra#!#19 +diane#!#18 +edna#!#18 +gina#!#18 +joan#!#18 +pat#!#18 +fanny#!#8 +mary#!#8 +~~END~~ + + +-- psql +-- +-- Test some cases involving whole-row Var referencing a subquery +-- +select foo from (select 1 offset 0) as foo; +GO +~~START~~ +record +(1) +~~END~~ + +select foo from (select null offset 0) as foo; +GO +~~START~~ +record +() +~~END~~ + +select foo from (select 'xyzzy',1,null offset 0) as foo; +GO +~~START~~ +record +(xyzzy,1,) +~~END~~ + + +-- +-- Test VALUES lists +-- +select * from master_dbo.onek, (values(147, 'RFAAAA'), (931, 'VJAAAA')) as v (i, j) + WHERE master_dbo.onek.unique1 = v.i and master_dbo.onek.stringu1 = v.j; +GO +~~START~~ +int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#name#!#name#!#name#!#int4#!#text +~~END~~ + +-- a more complex case +-- looks like we're coding lisp :-) +select * from master_dbo.onek, + (values ((select i from + (values(10000), (2), (389), (1000), (2000), ((select 10029))) as foo(i) + order by i asc limit 1))) bar (i) + where master_dbo.onek.unique1 = bar.i; +GO +~~START~~ +int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#name#!#name#!#name#!#int4 +2#!#326#!#0#!#2#!#2#!#2#!#2#!#2#!#2#!#2#!#2#!#4#!#5#!#CAAAAA#!#OMAAAA#!#OOOOxx#!#2 +~~END~~ + +-- try VALUES in a subquery +select * from master_dbo.onek + where (unique1,ten) in (values (1,1), (20,0), (99,9), (17,99)) + order by unique1; +GO +~~START~~ +int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#name#!#name#!#name +1#!#214#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#1#!#2#!#3#!#BAAAAA#!#GIAAAA#!#OOOOxx +20#!#306#!#0#!#0#!#0#!#0#!#0#!#20#!#20#!#20#!#20#!#0#!#1#!#UAAAAA#!#ULAAAA#!#OOOOxx +99#!#101#!#1#!#3#!#9#!#19#!#9#!#99#!#99#!#99#!#99#!#18#!#19#!#VDAAAA#!#XDAAAA#!#HHHHxx +~~END~~ + +-- VALUES is also legal as a standalone query or a set-operation member +VALUES (1,2), (3,4+4), (7,77.7); +GO +~~START~~ +int4#!#numeric +1#!#2 +3#!#8 +7#!#77.7 +~~END~~ + + +VALUES (1,2), (3,4+4), (7,77.7) +UNION ALL +SELECT 2+2, 57 +UNION ALL +TABLE master_dbo.int8_tbl; +GO +~~START~~ +int8#!#numeric +1#!#2 +3#!#8 +7#!#77.7 +4#!#57 +123#!#456 +123#!#4567890123456789 +4567890123456789#!#123 +4567890123456789#!#4567890123456789 +4567890123456789#!#-4567890123456789 +~~END~~ + + +-- corner case: VALUES with no columns +CREATE TEMP TABLE nocols(); +GO +INSERT INTO nocols DEFAULT VALUES; +GO +~~ROW COUNT: 1~~ + +SELECT * FROM nocols n, LATERAL (VALUES(n.*)) v; +GO +~~START~~ + + +~~END~~ + + +-- tsql +-- +-- Test ORDER BY options +-- +CREATE TABLE #foo (f1 int); +GO + +INSERT INTO #foo VALUES (42),(3),(10),(7),(null),(null),(1); +GO +~~ROW COUNT: 7~~ + + +SELECT * FROM #foo ORDER BY f1; +GO +~~START~~ +int + + +1 +3 +7 +10 +42 +~~END~~ + +SELECT * FROM #foo ORDER BY f1 ASC; -- same thing +GO +~~START~~ +int + + +1 +3 +7 +10 +42 +~~END~~ + +-- SELECT * FROM foo ORDER BY f1 NULLS FIRST; +-- GO +SELECT * FROM #foo ORDER BY f1 DESC; +GO +~~START~~ +int +42 +10 +7 +3 +1 + + +~~END~~ + + +-- SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; +-- GO +-- check if indexscans do the right things +CREATE INDEX fooi ON #foo (f1); +GO +select set_config('enable_sort', 'false', false); +GO +~~START~~ +text +off +~~END~~ + + +SELECT * FROM #foo ORDER BY f1; +GO +~~START~~ +int + + +1 +3 +7 +10 +42 +~~END~~ + +-- SELECT * FROM foo ORDER BY f1 NULLS FIRST; +-- GO +SELECT * FROM #foo ORDER BY f1 DESC; +GO +~~START~~ +int +42 +10 +7 +3 +1 + + +~~END~~ + + +-- SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; +-- GO +DROP INDEX fooi ON #foo; +GO +CREATE INDEX fooi ON #foo (f1 DESC); +GO + +SELECT * FROM #foo ORDER BY f1; +GO +~~START~~ +int + + +1 +3 +7 +10 +42 +~~END~~ + +-- SELECT * FROM foo ORDER BY f1 NULLS FIRST; +-- GO +SELECT * FROM #foo ORDER BY f1 DESC; +GO +~~START~~ +int +42 +10 +7 +3 +1 + + +~~END~~ + + +-- SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; +-- GO +DROP INDEX fooi ON #foo; +GO +-- CREATE INDEX fooi ON foo (f1 DESC NULLS LAST); +GO + +SELECT * FROM #foo ORDER BY f1; +GO +~~START~~ +int + + +1 +3 +7 +10 +42 +~~END~~ + +-- SELECT * FROM foo ORDER BY f1 NULLS FIRST; +-- GO +SELECT * FROM #foo ORDER BY f1 DESC; +GO +~~START~~ +int +42 +10 +7 +3 +1 + + +~~END~~ + + + +-- psql +-- SELECT * FROM foo ORDER BY f1 DESC NULLS LAST; +-- GO +-- +-- Test planning of some cases with partial indexes +-- +-- partial index is usable +explain (costs off) +select * from master_dbo.onek2 where unique2 = 11 and stringu1 = 'ATAAAA' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((unique2 = 11) AND (stringu1 = 'ATAAAA'::name)) +~~END~~ + +select * from master_dbo.onek2 where unique2 = 11 and stringu1 = 'ATAAAA' COLLATE "C"; +GO +~~START~~ +int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#name#!#name#!#name +494#!#11#!#0#!#2#!#4#!#14#!#4#!#94#!#94#!#494#!#494#!#8#!#9#!#ATAAAA#!#LAAAAA#!#VVVVxx +~~END~~ + +-- actually run the query with an analyze to use the partial index +explain (costs off, analyze on, timing off, summary off) +select * from master_dbo.onek2 where unique2 = 11 and stringu1 = 'ATAAAA' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 (actual rows=1 loops=1) + Filter: ((unique2 = 11) AND (stringu1 = 'ATAAAA'::name)) + Rows Removed by Filter: 999 +~~END~~ + +explain (costs off) +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 = 'ATAAAA' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((unique2 = 11) AND (stringu1 = 'ATAAAA'::name)) +~~END~~ + +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 = 'ATAAAA' COLLATE "C"; +GO +~~START~~ +int4 +11 +~~END~~ + +-- partial index predicate implies clause, so no need for retest +explain (costs off) +select * from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((stringu1 < 'B'::name) AND (unique2 = 11)) +~~END~~ + +select * from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#int4#!#name#!#name#!#name +494#!#11#!#0#!#2#!#4#!#14#!#4#!#94#!#94#!#494#!#494#!#8#!#9#!#ATAAAA#!#LAAAAA#!#VVVVxx +~~END~~ + +explain (costs off) +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((stringu1 < 'B'::name) AND (unique2 = 11)) +~~END~~ + +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +int4 +11 +~~END~~ + +-- but if it's an update target, must retest anyway +explain (costs off) +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C" for update; +GO +~~START~~ +text +LockRows + -> Seq Scan on onek2 + Filter: ((stringu1 < 'B'::name) AND (unique2 = 11)) +~~END~~ + +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C" for update; +GO +~~START~~ +int4 +11 +~~END~~ + +-- partial index is not applicable +explain (costs off) +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'C' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((stringu1 < 'C'::name) AND (unique2 = 11)) +~~END~~ + +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'C' COLLATE "C"; +GO +~~START~~ +int4 +11 +~~END~~ + +-- partial index implies clause, but bitmap scan must recheck predicate anyway +SET enable_indexscan TO off; +GO +explain (costs off) +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((stringu1 < 'B'::name) AND (unique2 = 11)) +~~END~~ + +select unique2 from master_dbo.onek2 where unique2 = 11 and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +int4 +11 +~~END~~ + +RESET enable_indexscan; +GO +-- check multi-index cases too +explain (costs off) +select unique1, unique2 from master_dbo.onek2 + where (unique2 = 11 or unique1 = 0) and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: ((stringu1 < 'B'::name) AND ((unique2 = 11) OR (unique1 = 0))) +~~END~~ + +select unique1, unique2 from master_dbo.onek2 + where (unique2 = 11 or unique1 = 0) and stringu1 < 'B' COLLATE "C"; +GO +~~START~~ +int4#!#int4 +494#!#11 +0#!#998 +~~END~~ + +explain (costs off) +select unique1, unique2 from master_dbo.onek2 + where (unique2 = 11 and stringu1 < 'B' COLLATE "C") or unique1 = 0; +GO +~~START~~ +text +Seq Scan on onek2 + Filter: (((unique2 = 11) AND (stringu1 < 'B'::name)) OR (unique1 = 0)) +~~END~~ + +select unique1, unique2 from master_dbo.onek2 + where (unique2 = 11 and stringu1 < 'B' COLLATE "C") or unique1 = 0; +GO +~~START~~ +int4#!#int4 +494#!#11 +0#!#998 +~~END~~ + + + +-- +-- Test some corner cases that have been known to confuse the planner +-- +-- ORDER BY on a constant doesn't really need any sorting +SELECT 1 AS x ORDER BY x; +GO +~~START~~ +int4 +1 +~~END~~ + + +-- But ORDER BY on a set-valued expression does +create function sillysrf(int) returns setof int as + 'values (1),(10),(2),($1)' language sql immutable; +GO + +select sillysrf(42); +GO +~~START~~ +int4 +1 +10 +2 +42 +~~END~~ + +select sillysrf(-1) order by 1; +GO +~~START~~ +int4 +-1 +1 +2 +10 +~~END~~ + + +drop function sillysrf(int); +GO + +-- X = X isn't a no-op, it's effectively X IS NOT NULL assuming = is strict +-- (see bug #5084) +select * from (values (2),(null),(1)) v(k) where k = k order by k; +GO +~~START~~ +int4 +1 +2 +~~END~~ + +select * from (values (2),(null),(1)) v(k) where k = k; +GO +~~START~~ +int4 +2 +1 +~~END~~ + + +-- Test partitioned tables with no partitions, which should be handled the +-- same as the non-inheritance case when expanding its RTE. +create table list_parted_tbl (a int,b int) partition by list (a); +GO +create table list_parted_tbl1 partition of list_parted_tbl + for values in (1) partition by list(b); +GO +explain (costs off) select * from list_parted_tbl; +GO +~~START~~ +text +Result + One-Time Filter: false +~~END~~ + +drop table list_parted_tbl; +GO diff --git a/test/JDBC/expected/pgr_select_distinct.out b/test/JDBC/expected/pgr_select_distinct.out new file mode 100644 index 0000000000..b709409a83 --- /dev/null +++ b/test/JDBC/expected/pgr_select_distinct.out @@ -0,0 +1,606 @@ + + +-- +-- SELECT_DISTINCT +-- +-- +-- awk '{print $3;}' onek.data | sort -n | uniq +-- +SELECT DISTINCT two FROM onek ORDER BY 1; +GO +~~START~~ +int +0 +1 +~~END~~ + + +-- +-- awk '{print $5;}' onek.data | sort -n | uniq +-- +SELECT DISTINCT ten FROM onek ORDER BY 1; +GO +~~START~~ +int +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +~~END~~ + + +-- +-- awk '{print $16;}' onek.data | sort -d | uniq +-- +SELECT DISTINCT string4 FROM onek ORDER BY 1; +GO +~~START~~ +varchar +AAAAxx +HHHHxx +OOOOxx +VVVVxx +~~END~~ + + +-- +-- awk '{print $3,$16,$5;}' onek.data | sort -d | uniq | +-- sort +0n -1 +1d -2 +2n -3 +-- +SELECT DISTINCT two, string4, ten + FROM onek + ORDER BY two asc, string4 asc, ten asc; +GO +~~START~~ +int#!#varchar#!#int +0#!#AAAAxx#!#0 +0#!#AAAAxx#!#2 +0#!#AAAAxx#!#4 +0#!#AAAAxx#!#6 +0#!#AAAAxx#!#8 +0#!#HHHHxx#!#0 +0#!#HHHHxx#!#2 +0#!#HHHHxx#!#4 +0#!#HHHHxx#!#6 +0#!#HHHHxx#!#8 +0#!#OOOOxx#!#0 +0#!#OOOOxx#!#2 +0#!#OOOOxx#!#4 +0#!#OOOOxx#!#6 +0#!#OOOOxx#!#8 +0#!#VVVVxx#!#0 +0#!#VVVVxx#!#2 +0#!#VVVVxx#!#4 +0#!#VVVVxx#!#6 +0#!#VVVVxx#!#8 +1#!#AAAAxx#!#1 +1#!#AAAAxx#!#3 +1#!#AAAAxx#!#5 +1#!#AAAAxx#!#7 +1#!#AAAAxx#!#9 +1#!#HHHHxx#!#1 +1#!#HHHHxx#!#3 +1#!#HHHHxx#!#5 +1#!#HHHHxx#!#7 +1#!#HHHHxx#!#9 +1#!#OOOOxx#!#1 +1#!#OOOOxx#!#3 +1#!#OOOOxx#!#5 +1#!#OOOOxx#!#7 +1#!#OOOOxx#!#9 +1#!#VVVVxx#!#1 +1#!#VVVVxx#!#3 +1#!#VVVVxx#!#5 +1#!#VVVVxx#!#7 +1#!#VVVVxx#!#9 +~~END~~ + + + + + +-- +-- awk '{print $2;}' person.data | +-- awk '{if(NF!=1){print $2;}else{print;}}' - emp.data | +-- awk '{if(NF!=1){print $2;}else{print;}}' - student.data | +-- awk 'BEGIN{FS=" ";}{if(NF!=1){print $5;}else{print;}}' - stud_emp.data | +-- sort -n -r | uniq +-- +-- SELECT DISTINCT p.age FROM person* p ORDER BY age using desc; +-- GO +-- +-- Check mentioning same column more than once +-- +select set_config('babelfishpg_tsql.explain_verbose', 'on', false); +GO +~~START~~ +text +on +~~END~~ + + +select set_config('babelfishpg_tsql.explain_costs', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL ON; +GO + +SELECT count(*) FROM (SELECT DISTINCT two, four, two FROM tenk1) ss; +GO +~~START~~ +text +Query Text: SELECT count(*) FROM (SELECT DISTINCT two, four, two FROM tenk1) ss +Aggregate + Output: count(*) + -> HashAggregate + Output: tenk1.two, tenk1.four, tenk1.two + Group Key: tenk1.two, tenk1.four, tenk1.two + -> Seq Scan on master_dbo.tenk1 + Output: tenk1.two, tenk1.four, tenk1.two +~~END~~ + + +SELECT count(*) FROM + (SELECT DISTINCT two, four, two FROM tenk1) ss; +GO +~~START~~ +text +Query Text: SELECT count(*) FROM + (SELECT DISTINCT two, four, two FROM tenk1) ss +Aggregate + Output: count(*) + -> HashAggregate + Output: tenk1.two, tenk1.four, tenk1.two + Group Key: tenk1.two, tenk1.four, tenk1.two + -> Seq Scan on master_dbo.tenk1 + Output: tenk1.two, tenk1.four, tenk1.two +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL OFF; +GO + + +-- +-- Compare results between plans using sorting and plans using hash +-- aggregation. Force spilling in both cases by setting work_mem low. +-- +select set_config('work_mem', '64kB', false); +GO +~~START~~ +text +64kB +~~END~~ + + +-- Produce results with sorting. +select set_config('enable_hashagg', 'FALSE', false); +GO +~~START~~ +text +off +~~END~~ + + + + +-- select set_config('jit_above_cost', '0', false); +-- GO +select set_config('babelfishpg_tsql.explain_costs', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL ON; +GO + +SELECT DISTINCT g%1000 FROM generate_series(0,9999) g; +GO +~~START~~ +text +Query Text: SELECT DISTINCT g%1000 FROM generate_series(0,9999) g +Unique + Output: ((g % 1000)) + -> Sort + Output: ((g % 1000)) + Sort Key: ((g.g % 1000)) + -> Function Scan on pg_catalog.generate_series g + Output: (g % 1000) + Function Call: generate_series(0, 9999) +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL OFF; +GO + +SELECT DISTINCT g%1000 INTO distinct_group_1 FROM generate_series(0,9999) g; +GO + + +-- -- SET jit_above_cost TO DEFAULT; +-- select set_config('jit_above_cost', 'DEFAULT', false); +-- GO +SELECT DISTINCT cast((g%1000) as varchar(max)) INTO distinct_group_2 FROM generate_series(0,9999) g; +GO + +select set_config('enable_hashagg', 'TRUE', false); +GO +~~START~~ +text +on +~~END~~ + + + +-- Produce results with hash aggregation. +select set_config('enable_sort', 'FALSE', false); +GO +~~START~~ +text +off +~~END~~ + + + +-- select set_config('jit_above_cost', '0', false); +select set_config('babelfishpg_tsql.explain_costs', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL ON; +GO + +SELECT DISTINCT g%1000 FROM generate_series(0,9999) g; +GO +~~START~~ +text +Query Text: SELECT DISTINCT g%1000 FROM generate_series(0,9999) g +HashAggregate + Output: ((g % 1000)) + Group Key: (g.g % 1000) + -> Function Scan on pg_catalog.generate_series g + Output: (g % 1000) + Function Call: generate_series(0, 9999) +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL OFF; +GO + +SELECT DISTINCT g%1000 INTO distinct_hash_1 FROM generate_series(0,9999) g; +GO + + + +-- select set_config('jit_above_cost', 'DEFAULT', false); +-- GO +SELECT DISTINCT cast((g%1000) as varchar(max)) INTO distinct_hash_2 FROM generate_series(0,9999) g; +GO + +select set_config('enable_sort', 'TRUE', false); +GO +~~START~~ +text +on +~~END~~ + + +-- psql +SET work_mem TO DEFAULT; +GO + + +-- tsql + +-- Compare results +(SELECT * FROM distinct_hash_1 EXCEPT SELECT * FROM distinct_group_1) + UNION ALL +(SELECT * FROM distinct_group_1 EXCEPT SELECT * FROM distinct_hash_1); +GO +~~START~~ +int +~~END~~ + + +(SELECT * FROM distinct_hash_1 EXCEPT SELECT * FROM distinct_group_1) + UNION ALL +(SELECT * FROM distinct_group_1 EXCEPT SELECT * FROM distinct_hash_1); +GO +~~START~~ +int +~~END~~ + + +DROP TABLE distinct_hash_1; +GO +DROP TABLE distinct_hash_2; +GO +DROP TABLE distinct_group_1; +GO +DROP TABLE distinct_group_2; +GO + + +-- Test parallel DISTINCT +select set_config('parallel_tuple_cost', '0', false); +GO +~~START~~ +text +0 +~~END~~ + +select set_config('parallel_setup_cost', '0', false); +GO +~~START~~ +text +0 +~~END~~ + +select set_config('min_parallel_table_scan_size', '0', false); +GO +~~START~~ +text +0 +~~END~~ + +select set_config('max_parallel_workers_per_gather', '2', false); +GO +~~START~~ +text +2 +~~END~~ + + + + +-- Ensure we get a parallel plan +select set_config('babelfishpg_tsql.explain_costs', 'off', false); +GO +~~START~~ +text +off +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL ON; +GO + +SELECT DISTINCT four FROM tenk1; +GO +~~START~~ +text +Query Text: SELECT DISTINCT four FROM tenk1 +Unique + -> Sort + Sort Key: four + -> Gather + Workers Planned: 2 + -> HashAggregate + Group Key: four + -> Parallel Seq Scan on tenk1 +~~END~~ + + +SET BABELFISH_SHOWPLAN_ALL OFF; +GO + +-- Ensure the parallel plan produces the correct results +SELECT DISTINCT four FROM tenk1; +GO +~~START~~ +int +0 +1 +2 +3 +~~END~~ + + + +-- psql +-- Since Tsql function does not support specify parallel safe mode, we execute the following tests in psql +-- Ensure the parallel plan produces the correct results +SELECT DISTINCT four FROM master_dbo.tenk1; +GO +~~START~~ +int4 +0 +1 +3 +2 +~~END~~ + + +CREATE OR REPLACE FUNCTION distinct_func(a INT) RETURNS INT AS $$ + BEGIN + RETURN a; + END; +$$ LANGUAGE plpgsql PARALLEL UNSAFE; +GO + +-- Ensure we don't do parallel distinct with a parallel unsafe function +EXPLAIN (COSTS OFF) +SELECT DISTINCT distinct_func(1) FROM master_dbo.tenk1; +GO +~~START~~ +text +Unique + -> Sort + Sort Key: (distinct_func(1)) + -> Seq Scan on tenk1 +~~END~~ + + +-- make the function parallel safe +CREATE OR REPLACE FUNCTION distinct_func(a INT) RETURNS INT AS $$ + BEGIN + RETURN a; + END; +$$ LANGUAGE plpgsql PARALLEL SAFE; +GO + +-- Ensure we do parallel distinct now that the function is parallel safe +EXPLAIN (COSTS OFF) +SELECT DISTINCT distinct_func(1) FROM master_dbo.tenk1; +GO +~~START~~ +text +Unique + -> Sort + Sort Key: (distinct_func(1)) + -> Seq Scan on tenk1 +~~END~~ + + +RESET max_parallel_workers_per_gather; +GO +RESET min_parallel_table_scan_size; +GO +RESET parallel_setup_cost; +GO +RESET parallel_tuple_cost; +GO + + +-- +-- Also, some tests of IS DISTINCT FROM, which doesn't quite deserve its +-- very own regression file. +-- +CREATE TEMP TABLE disttable (f1 integer); +GO +INSERT INTO DISTTABLE VALUES(1); +GO +~~ROW COUNT: 1~~ + +INSERT INTO DISTTABLE VALUES(2); +GO +~~ROW COUNT: 1~~ + +INSERT INTO DISTTABLE VALUES(3); +GO +~~ROW COUNT: 1~~ + +INSERT INTO DISTTABLE VALUES(NULL); +GO +~~ROW COUNT: 1~~ + + +-- basic cases +SELECT f1, f1 IS DISTINCT FROM 2 as "not 2" FROM disttable; +GO +~~START~~ +int4#!#bool +1#!#t +2#!#f +3#!#t +#!#t +~~END~~ + +SELECT f1, f1 IS DISTINCT FROM NULL as "not null" FROM disttable; +GO +~~START~~ +int4#!#bool +1#!#t +2#!#t +3#!#t +#!#f +~~END~~ + +SELECT f1, f1 IS DISTINCT FROM f1 as "false" FROM disttable; +GO +~~START~~ +int4#!#bool +1#!#f +2#!#f +3#!#f +#!#f +~~END~~ + +SELECT f1, f1 IS DISTINCT FROM f1+1 as "not null" FROM disttable; +GO +~~START~~ +int4#!#bool +1#!#t +2#!#t +3#!#t +#!#f +~~END~~ + + +-- check that optimizer constant-folds it properly +SELECT 1 IS DISTINCT FROM 2 as "yes"; +GO +~~START~~ +bool +t +~~END~~ + +SELECT 2 IS DISTINCT FROM 2 as "no"; +GO +~~START~~ +bool +f +~~END~~ + +SELECT 2 IS DISTINCT FROM null as "yes"; +GO +~~START~~ +bool +t +~~END~~ + +SELECT null IS DISTINCT FROM null as "no"; +GO +~~START~~ +bool +f +~~END~~ + + +-- negated form +SELECT 1 IS NOT DISTINCT FROM 2 as "no"; +GO +~~START~~ +bool +f +~~END~~ + +SELECT 2 IS NOT DISTINCT FROM 2 as "yes"; +GO +~~START~~ +bool +t +~~END~~ + +SELECT 2 IS NOT DISTINCT FROM null as "no"; +GO +~~START~~ +bool +f +~~END~~ + +SELECT null IS NOT DISTINCT FROM null as "yes"; +GO +~~START~~ +bool +t +~~END~~ + diff --git a/test/JDBC/expected/pgr_select_distinct_on.out b/test/JDBC/expected/pgr_select_distinct_on.out new file mode 100644 index 0000000000..ec9a7a3bb4 --- /dev/null +++ b/test/JDBC/expected/pgr_select_distinct_on.out @@ -0,0 +1,89 @@ +-- psql +-- +-- SELECT_DISTINCT_ON +-- +SELECT DISTINCT ON (string4) string4, two, ten + FROM master_dbo.onek + ORDER BY string4 asc, two desc, ten asc; +GO +~~START~~ +name#!#int4#!#int4 +AAAAxx#!#1#!#1 +HHHHxx#!#1#!#1 +OOOOxx#!#1#!#1 +VVVVxx#!#1#!#1 +~~END~~ + + +-- this will fail due to conflict of ordering requirements +SELECT DISTINCT ON (string4, ten) string4, two, ten + FROM master_dbo.onek + ORDER BY string4 asc, two asc, ten asc; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions + Position: 89 + Server SQLState: 42P10)~~ + + +SELECT DISTINCT ON (string4, ten) string4, ten, two + FROM master_dbo.onek + ORDER BY string4 asc, ten desc, two asc; +GO +~~START~~ +name#!#int4#!#int4 +AAAAxx#!#9#!#1 +AAAAxx#!#8#!#0 +AAAAxx#!#7#!#1 +AAAAxx#!#6#!#0 +AAAAxx#!#5#!#1 +AAAAxx#!#4#!#0 +AAAAxx#!#3#!#1 +AAAAxx#!#2#!#0 +AAAAxx#!#1#!#1 +AAAAxx#!#0#!#0 +HHHHxx#!#9#!#1 +HHHHxx#!#8#!#0 +HHHHxx#!#7#!#1 +HHHHxx#!#6#!#0 +HHHHxx#!#5#!#1 +HHHHxx#!#4#!#0 +HHHHxx#!#3#!#1 +HHHHxx#!#2#!#0 +HHHHxx#!#1#!#1 +HHHHxx#!#0#!#0 +OOOOxx#!#9#!#1 +OOOOxx#!#8#!#0 +OOOOxx#!#7#!#1 +OOOOxx#!#6#!#0 +OOOOxx#!#5#!#1 +OOOOxx#!#4#!#0 +OOOOxx#!#3#!#1 +OOOOxx#!#2#!#0 +OOOOxx#!#1#!#1 +OOOOxx#!#0#!#0 +VVVVxx#!#9#!#1 +VVVVxx#!#8#!#0 +VVVVxx#!#7#!#1 +VVVVxx#!#6#!#0 +VVVVxx#!#5#!#1 +VVVVxx#!#4#!#0 +VVVVxx#!#3#!#1 +VVVVxx#!#2#!#0 +VVVVxx#!#1#!#1 +VVVVxx#!#0#!#0 +~~END~~ + + +-- bug #5049: early 8.4.x chokes on volatile DISTINCT ON clauses +select distinct on (1) floor(random()) as r, f1 from int4_tbl order by 1,2; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "int4_tbl" does not exist + Position: 119 + Server SQLState: 42P01)~~ + + + diff --git a/test/JDBC/expected/pgr_select_having.out b/test/JDBC/expected/pgr_select_having.out new file mode 100644 index 0000000000..b20e2be38a --- /dev/null +++ b/test/JDBC/expected/pgr_select_having.out @@ -0,0 +1,148 @@ + +-- +-- SELECT_HAVING +-- +-- load test data +CREATE TABLE test_having (a int, b int, c char(8), d char); +GO +INSERT INTO test_having VALUES (0, 1, 'XXXX', 'A'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (1, 2, 'AAAA', 'b'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (2, 2, 'AAAA', 'c'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (3, 3, 'BBBB', 'D'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (4, 3, 'BBBB', 'e'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (5, 3, 'bbbb', 'F'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (6, 4, 'cccc', 'g'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (7, 4, 'cccc', 'h'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (8, 4, 'CCCC', 'I'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_having VALUES (9, 4, 'CCCC', 'j'); +GO +~~ROW COUNT: 1~~ + + +SELECT b, c FROM test_having + GROUP BY b, c HAVING count(*) = 1 ORDER BY b, c; +GO +~~START~~ +int#!#char +1#!#XXXX +~~END~~ + + +-- HAVING is effectively equivalent to WHERE in this case +SELECT b, c FROM test_having + GROUP BY b, c HAVING b = 3 ORDER BY b, c; +GO +~~START~~ +int#!#char +3#!#BBBB +~~END~~ + + +SELECT lower(c), count(c) FROM test_having + GROUP BY lower(c) HAVING count(*) > 2 OR min(a) = max(a) + ORDER BY lower(c); +GO +~~START~~ +text#!#int +bbbb #!#3 +cccc #!#4 +xxxx #!#1 +~~END~~ + + +SELECT c, max(a) FROM test_having + GROUP BY c HAVING count(*) > 2 OR min(a) = max(a) + ORDER BY c; +GO +~~START~~ +char#!#int +BBBB #!#5 +cccc #!#9 +XXXX #!#0 +~~END~~ + + + +-- test degenerate cases involving HAVING without GROUP BY +-- Per SQL spec, these should generate 0 or 1 row, even without aggregates +SELECT min(a), max(a) FROM test_having HAVING min(a) = max(a); +GO +~~START~~ +int#!#int +~~END~~ + +SELECT min(a), max(a) FROM test_having HAVING min(a) < max(a); +GO +~~START~~ +int#!#int +0#!#9 +~~END~~ + + +-- errors: ungrouped column references +SELECT a FROM test_having HAVING min(a) < max(a); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "test_having.a" must appear in the GROUP BY clause or be used in an aggregate function)~~ + +SELECT 1 AS one FROM test_having HAVING a > 1; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "test_having.a" must appear in the GROUP BY clause or be used in an aggregate function)~~ + + +-- the really degenerate case: need not scan table at all +SELECT 1 AS one FROM test_having HAVING 1 > 2; +GO +~~START~~ +int +~~END~~ + +SELECT 1 AS one FROM test_having HAVING 1 < 2; +GO +~~START~~ +int +1 +~~END~~ + + +-- and just to prove that we aren't scanning the table: +SELECT 1 AS one FROM test_having WHERE 1/a = 1 HAVING 1 < 2; +GO +~~START~~ +int +1 +~~END~~ + + +DROP TABLE test_having; +GO diff --git a/test/JDBC/expected/pgr_select_implicit.out b/test/JDBC/expected/pgr_select_implicit.out new file mode 100644 index 0000000000..d718a2e842 --- /dev/null +++ b/test/JDBC/expected/pgr_select_implicit.out @@ -0,0 +1,432 @@ + +-- +-- SELECT_IMPLICIT +-- Test cases for queries with ordering terms missing from the target list. +-- This used to be called "junkfilter.sql". +-- The parser uses the term "resjunk" to handle these cases. +-- - thomas 1998-07-09 +-- +-- load test data +CREATE TABLE test_missing_target (a int, b int, c char(8), d char); +GO +INSERT INTO test_missing_target VALUES (0, 1, 'XXXX', 'A'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (1, 2, 'ABAB', 'b'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (2, 2, 'ABAB', 'c'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (3, 3, 'BBBB', 'D'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (4, 3, 'BBBB', 'e'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (5, 3, 'bbbb', 'F'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (6, 4, 'cccc', 'g'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (7, 4, 'cccc', 'h'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (8, 4, 'CCCC', 'I'); +GO +~~ROW COUNT: 1~~ + +INSERT INTO test_missing_target VALUES (9, 4, 'CCCC', 'j'); +GO +~~ROW COUNT: 1~~ + + + +-- w/ existing GROUP BY target +SELECT c, count(*) FROM test_missing_target GROUP BY test_missing_target.c ORDER BY c; +GO +~~START~~ +char#!#int +ABAB #!#2 +BBBB #!#3 +cccc #!#4 +XXXX #!#1 +~~END~~ + + +-- w/o existing GROUP BY target using a relation name in GROUP BY clause +SELECT count(*) FROM test_missing_target GROUP BY test_missing_target.c ORDER BY c; +GO +~~START~~ +int +2 +3 +4 +1 +~~END~~ + + +-- w/o existing GROUP BY target and w/o existing a different ORDER BY target +-- failure expected +SELECT count(*) FROM test_missing_target GROUP BY a ORDER BY b; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "test_missing_target.b" must appear in the GROUP BY clause or be used in an aggregate function)~~ + + +-- w/o existing GROUP BY target and w/o existing same ORDER BY target +SELECT count(*) FROM test_missing_target GROUP BY b ORDER BY b; +GO +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +-- w/ existing GROUP BY target using a relation name in target +SELECT test_missing_target.b, count(*) + FROM test_missing_target GROUP BY b ORDER BY b; +GO +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +~~END~~ + + +-- w/o existing GROUP BY target +SELECT c FROM test_missing_target ORDER BY a; +GO +~~START~~ +char +XXXX +ABAB +ABAB +BBBB +BBBB +bbbb +cccc +cccc +CCCC +CCCC +~~END~~ + + +-- w/o existing ORDER BY target +SELECT count(*) FROM test_missing_target GROUP BY b ORDER BY b desc; +GO +~~START~~ +int +4 +3 +2 +1 +~~END~~ + + +-- group using reference number +SELECT count(*) FROM test_missing_target ORDER BY 1 desc; +GO +~~START~~ +int +10 +~~END~~ + + +-- order using reference number +SELECT c, count(*) FROM test_missing_target GROUP BY 1 ORDER BY 1; +GO +~~START~~ +char#!#int +ABAB #!#2 +BBBB #!#3 +cccc #!#4 +XXXX #!#1 +~~END~~ + + +-- group using reference number out of range +-- failure expected +SELECT c, count(*) FROM test_missing_target GROUP BY 3; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: GROUP BY position 3 is not in select list)~~ + + +-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition +-- failure expected +SELECT count(*) FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY b ORDER BY b; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column reference "b" is ambiguous)~~ + + +-- order w/ target under ambiguous condition +-- failure NOT expected +SELECT a, a FROM test_missing_target + ORDER BY a; +GO +~~START~~ +int#!#int +0#!#0 +1#!#1 +2#!#2 +3#!#3 +4#!#4 +5#!#5 +6#!#6 +7#!#7 +8#!#8 +9#!#9 +~~END~~ + + +-- order expression w/ target under ambiguous condition +-- failure NOT expected +SELECT a/2, a/2 FROM test_missing_target + ORDER BY a/2; +GO +~~START~~ +int#!#int +0#!#0 +0#!#0 +1#!#1 +1#!#1 +2#!#2 +2#!#2 +3#!#3 +3#!#3 +4#!#4 +4#!#4 +~~END~~ + + +-- group expression w/ target under ambiguous condition +-- failure NOT expected +SELECT a/2, a/2 FROM test_missing_target + GROUP BY a/2 ORDER BY a/2; +GO +~~START~~ +int#!#int +0#!#0 +1#!#1 +2#!#2 +3#!#3 +4#!#4 +~~END~~ + + +-- group w/ existing GROUP BY target under ambiguous condition +SELECT x.b, count(*) FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY x.b ORDER BY x.b; +GO +~~START~~ +int#!#int +1#!#1 +2#!#2 +3#!#3 +4#!#4 +~~END~~ + + +-- group w/o existing GROUP BY target under ambiguous condition +SELECT count(*) FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY x.b ORDER BY x.b; +GO +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + +-- group w/o existing GROUP BY target under ambiguous condition +-- into a table +SELECT count(*) INTO test_missing_target2 +FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY x.b ORDER BY x.b; +GO +SELECT * FROM test_missing_target2; +GO +~~START~~ +int +1 +2 +3 +4 +~~END~~ + + + + +-- Functions and expressions +-- w/ existing GROUP BY target +SELECT a%2, count(b) FROM test_missing_target +GROUP BY test_missing_target.a%2 +ORDER BY test_missing_target.a%2; +GO +~~START~~ +int#!#int +0#!#5 +1#!#5 +~~END~~ + + +-- w/o existing GROUP BY target using a relation name in GROUP BY clause +SELECT count(c) FROM test_missing_target +GROUP BY lower(test_missing_target.c) +ORDER BY lower(test_missing_target.c); +GO +~~START~~ +int +2 +3 +4 +1 +~~END~~ + + +-- w/o existing GROUP BY target and w/o existing a different ORDER BY target +-- failure expected +SELECT count(a) FROM test_missing_target GROUP BY a ORDER BY b; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "test_missing_target.b" must appear in the GROUP BY clause or be used in an aggregate function)~~ + + +-- w/o existing GROUP BY target and w/o existing same ORDER BY target +SELECT count(b) FROM test_missing_target GROUP BY b/2 ORDER BY b/2; +GO +~~START~~ +int +1 +5 +4 +~~END~~ + + +-- w/ existing GROUP BY target using a relation name in target +SELECT lower(test_missing_target.c), count(c) + FROM test_missing_target GROUP BY lower(c) ORDER BY lower(c); +GO +~~START~~ +text#!#int +abab #!#2 +bbbb #!#3 +cccc #!#4 +xxxx #!#1 +~~END~~ + + +-- w/o existing GROUP BY target +SELECT a FROM test_missing_target ORDER BY upper(d); +GO +~~START~~ +int +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +~~END~~ + + +-- w/o existing ORDER BY target +SELECT count(b) FROM test_missing_target + GROUP BY (b + 1) / 2 ORDER BY (b + 1) / 2 desc; +GO +~~START~~ +int +7 +3 +~~END~~ + + +-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition +-- failure expected +SELECT count(x.a) FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY b/2 ORDER BY b/2; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column reference "b" is ambiguous)~~ + + +-- group w/ existing GROUP BY target under ambiguous condition +SELECT x.b/2, count(x.b) FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY x.b/2 ORDER BY x.b/2; +GO +~~START~~ +int#!#int +0#!#1 +1#!#5 +2#!#4 +~~END~~ + + +-- group w/o existing GROUP BY target under ambiguous condition +-- failure expected due to ambiguous b in count(b) +SELECT count(b) FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY x.b/2; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column reference "b" is ambiguous)~~ + + +-- group w/o existing GROUP BY target under ambiguous condition +-- into a table +SELECT count(x.b) INTO test_missing_target3 +FROM test_missing_target x, test_missing_target y + WHERE x.a = y.a + GROUP BY x.b/2 ORDER BY x.b/2 +SELECT * FROM test_missing_target3; +GO +~~START~~ +int +1 +5 +4 +~~END~~ + + +-- Cleanup +DROP TABLE test_missing_target; +GO +DROP TABLE test_missing_target2; +GO +DROP TABLE test_missing_target3; +GO diff --git a/test/JDBC/expected/pgr_select_into.out b/test/JDBC/expected/pgr_select_into.out new file mode 100644 index 0000000000..5f9143b778 --- /dev/null +++ b/test/JDBC/expected/pgr_select_into.out @@ -0,0 +1,403 @@ + +-- psql + +-- +-- SELECT_INTO +-- +SELECT * + INTO TABLE sitmp1 + FROM master_dbo.onek + WHERE master_dbo.onek.unique1 < 2; +GO +~~ROW COUNT: 2~~ + + +DROP TABLE sitmp1; +GO + +SELECT * + INTO TABLE sitmp1 + FROM master_dbo.onek2 + WHERE master_dbo.onek2.unique1 < 2; +GO +~~ROW COUNT: 2~~ + + +DROP TABLE sitmp1; +GO + +-- +-- SELECT INTO and INSERT permission, if owner is not allowed to insert. +-- +CREATE SCHEMA selinto_schema; +GO +CREATE USER regress_selinto_user; +GO +ALTER DEFAULT PRIVILEGES FOR ROLE regress_selinto_user + REVOKE INSERT ON TABLES FROM regress_selinto_user; +GO +GRANT ALL ON SCHEMA selinto_schema TO public; +GO + +SET SESSION AUTHORIZATION regress_selinto_user; +GO +-- WITH DATA, passes. +CREATE TABLE selinto_schema.tbl_withdata1 (a) + AS SELECT generate_series(1,3) WITH DATA; +GO +~~ROW COUNT: 3~~ + +INSERT INTO selinto_schema.tbl_withdata1 VALUES (4); +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: permission denied for table tbl_withdata1 + Server SQLState: 42501)~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE selinto_schema.tbl_withdata2 (a) AS + SELECT generate_series(1,3) WITH DATA; +GO +~~START~~ +text +ProjectSet (actual rows=3 loops=1) + -> Result (actual rows=1 loops=1) +~~END~~ + +-- WITH NO DATA, passes. +CREATE TABLE selinto_schema.tbl_nodata1 (a) AS + SELECT generate_series(1,3) WITH NO DATA; +GO +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE selinto_schema.tbl_nodata2 (a) AS + SELECT generate_series(1,3) WITH NO DATA; +GO +~~START~~ +text +ProjectSet (never executed) + -> Result (never executed) +~~END~~ + +-- EXECUTE and WITH DATA, passes. +PREPARE data_sel AS SELECT generate_series(1,3); +GO +CREATE TABLE selinto_schema.tbl_withdata3 (a) AS + EXECUTE data_sel WITH DATA; +GO +~~ROW COUNT: 3~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE selinto_schema.tbl_withdata4 (a) AS + EXECUTE data_sel WITH DATA; +GO +~~START~~ +text +ProjectSet (actual rows=3 loops=1) + -> Result (actual rows=1 loops=1) +~~END~~ + +-- EXECUTE and WITH NO DATA, passes. +CREATE TABLE selinto_schema.tbl_nodata3 (a) AS + EXECUTE data_sel WITH NO DATA; +GO +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE selinto_schema.tbl_nodata4 (a) AS + EXECUTE data_sel WITH NO DATA; +GO +~~START~~ +text +ProjectSet (never executed) + -> Result (never executed) +~~END~~ + +RESET SESSION AUTHORIZATION; +GO + +ALTER DEFAULT PRIVILEGES FOR ROLE regress_selinto_user + GRANT INSERT ON TABLES TO regress_selinto_user; +GO + +SET SESSION AUTHORIZATION regress_selinto_user; +GO +RESET SESSION AUTHORIZATION; +GO + +DEALLOCATE data_sel; +GO +DROP SCHEMA selinto_schema CASCADE; +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: drop cascades to 8 other objects Server SQLState: 00000)~~ + +DROP USER regress_selinto_user; +GO + +-- Tests for WITH NO DATA and column name consistency +CREATE TABLE ctas_base (i int, j int); +GO +INSERT INTO ctas_base VALUES (1, 2); +GO +~~ROW COUNT: 1~~ + +CREATE TABLE ctas_nodata (ii, jj, kk) AS SELECT i, j FROM ctas_base; -- Error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: too many column names were specified + Server SQLState: 42601)~~ + +CREATE TABLE ctas_nodata (ii, jj, kk) AS SELECT i, j FROM ctas_base WITH NO DATA; -- Error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: too many column names were specified + Server SQLState: 42601)~~ + +CREATE TABLE ctas_nodata (ii, jj) AS SELECT i, j FROM ctas_base; -- OK +GO +~~ROW COUNT: 1~~ + +CREATE TABLE ctas_nodata_2 (ii, jj) AS SELECT i, j FROM ctas_base WITH NO DATA; -- OK +GO +CREATE TABLE ctas_nodata_3 (ii) AS SELECT i, j FROM ctas_base; -- OK +GO +~~ROW COUNT: 1~~ + +CREATE TABLE ctas_nodata_4 (ii) AS SELECT i, j FROM ctas_base WITH NO DATA; -- OK +GO +SELECT * FROM ctas_nodata; +GO +~~START~~ +int4#!#int4 +1#!#2 +~~END~~ + +SELECT * FROM ctas_nodata_2; +GO +~~START~~ +int4#!#int4 +~~END~~ + +SELECT * FROM ctas_nodata_3; +GO +~~START~~ +int4#!#int4 +1#!#2 +~~END~~ + +SELECT * FROM ctas_nodata_4; +GO +~~START~~ +int4#!#int4 +~~END~~ + +DROP TABLE ctas_base; +GO +DROP TABLE ctas_nodata; +GO +DROP TABLE ctas_nodata_2; +GO +DROP TABLE ctas_nodata_3; +GO +DROP TABLE ctas_nodata_4; +GO + +-- +-- CREATE TABLE AS/SELECT INTO as last command in a SQL function +-- have been known to cause problems +-- +CREATE FUNCTION make_table() RETURNS VOID +AS $$ + CREATE TABLE created_table AS SELECT * FROM master_dbo.int8_tbl; +$$ LANGUAGE SQL; +GO + +SELECT make_table(); +GO +~~START~~ +void + +~~END~~ + + +SELECT * FROM created_table; +GO +~~START~~ +int8#!#int8 +123#!#456 +123#!#4567890123456789 +4567890123456789#!#123 +4567890123456789#!#4567890123456789 +4567890123456789#!#-4567890123456789 +~~END~~ + + +-- Try EXPLAIN ANALYZE SELECT INTO and EXPLAIN ANALYZE CREATE TABLE AS +-- WITH NO DATA, but hide the outputs since they won't be stable. +DO $$ +BEGIN + EXECUTE 'EXPLAIN ANALYZE SELECT * INTO TABLE easi FROM master_dbo.int8_tbl'; + EXECUTE 'EXPLAIN ANALYZE CREATE TABLE easi2 AS SELECT * FROM master_dbo.int8_tbl WITH NO DATA'; +END$$; +GO + +DROP TABLE created_table; +GO +DROP TABLE easi, easi2; +GO + +-- +-- Disallowed uses of SELECT ... INTO. All should fail +-- +DECLARE foo CURSOR FOR SELECT 1 INTO master_dbo.int4_tbl; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: SELECT ... INTO is not allowed here + Position: 100 + Server SQLState: 42601)~~ + +COPY (SELECT 1 INTO frak UNION SELECT 2) TO 'blob'; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: COPY (SELECT INTO) is not supported + Server SQLState: 0A000)~~ + +SELECT * FROM (SELECT 1 INTO f) bar; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: SELECT ... INTO is not allowed here + Position: 30 + Server SQLState: 42601)~~ + +CREATE VIEW foo AS SELECT 1 INTO master_dbo.int4_tbl; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: views must not contain SELECT INTO + Server SQLState: 0A000)~~ + +INSERT INTO master_dbo.int4_tbl SELECT 1 INTO f; +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: SELECT ... INTO is not allowed here + Position: 47 + Server SQLState: 42601)~~ + + +-- Test CREATE TABLE AS ... IF NOT EXISTS +CREATE TABLE ctas_ine_tbl AS SELECT 1; +GO +~~ROW COUNT: 1~~ + +CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0; -- error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "ctas_ine_tbl" already exists + Server SQLState: 42P07)~~ + +CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0; -- ok +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "ctas_ine_tbl" already exists + Server SQLState: 42P07)~~ + +CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- ok +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0; -- error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "ctas_ine_tbl" already exists + Server SQLState: 42P07)~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0; -- ok +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +~~START~~ +text +~~END~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "ctas_ine_tbl" already exists + Server SQLState: 42P07)~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS SELECT 1 / 0 WITH NO DATA; -- ok +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +~~START~~ +text +~~END~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +PREPARE ctas_ine_query AS SELECT 1 / 0; +GO +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE ctas_ine_tbl AS EXECUTE ctas_ine_query; -- error +GO +~~ERROR (Code: 0)~~ + +~~ERROR (Message: ERROR: relation "ctas_ine_tbl" already exists + Server SQLState: 42P07)~~ + +EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) + CREATE TABLE IF NOT EXISTS ctas_ine_tbl AS EXECUTE ctas_ine_query; -- ok +GO +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +~~START~~ +text +~~END~~ + +~~WARNING (Code: 0)~~ + +~~WARNING (Message: relation "ctas_ine_tbl" already exists, skipping Server SQLState: 42P07)~~ + +DROP TABLE ctas_ine_tbl; +GO diff --git a/test/JDBC/expected/pgr_zzz_clean_up.out b/test/JDBC/expected/pgr_zzz_clean_up.out new file mode 100644 index 0000000000..3d0fad020a --- /dev/null +++ b/test/JDBC/expected/pgr_zzz_clean_up.out @@ -0,0 +1,53 @@ +DROP TABLE road; +GO + +DROP TABLE aggtest; +GO + +DROP TABLE stud_emp; +GO + +DROP TABLE student; +GO + +DROP TABLE emp; +GO + +DROP TABLE person; +GO + +DROP TABLE tenk2; +GO + +DROP TABLE tenk1; +GO + +DROP TABLE onek2; +GO + +DROP TABLE onek; +GO + +DROP TABLE VARCHAR_TBL; +GO + +DROP TABLE TEXT_TBL; +GO + +DROP TABLE POINT_TBL; +GO + +DROP TABLE INT8_TBL; +GO + +DROP TABLE INT4_TBL; +GO + +DROP TABLE INT2_TBL; +GO + +DROP TABLE FLOAT8_TBL; +GO + +DROP TABLE CHAR_TBL; +GO diff --git a/test/JDBC/expected/pivot-vu-cleanup.out b/test/JDBC/expected/pivot-vu-cleanup.out new file mode 100644 index 0000000000..390cb4b053 --- /dev/null +++ b/test/JDBC/expected/pivot-vu-cleanup.out @@ -0,0 +1,23 @@ +use pivot_test +GO + +drop table pivot_insert_into; +GO + +drop table pivot_select_into; +GO + +drop procedure top_n_pivot; +GO + +drop function test_table_valued_function; +GO + +drop table StoreReceipt; +GO + +use master +GO + +drop database pivot_test +GO diff --git a/test/JDBC/expected/pivot-vu-prepare.out b/test/JDBC/expected/pivot-vu-prepare.out new file mode 100644 index 0000000000..ea731f88d9 --- /dev/null +++ b/test/JDBC/expected/pivot-vu-prepare.out @@ -0,0 +1,875 @@ +create database pivot_test +GO + +use pivot_test +GO + +create table StoreReceipt ( + OrderID INT, + ItemID INT, + Price DECIMAL(6,2), + EmployeeID INT, + StoreID INT, + ManufactureID INT, + PurchaseDate DATE +); +GO + + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (1, 2006, 485.14, 252, 7, 1209, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (2, 2146, 681.23, 296, 9, 1234, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (3, 2074, 960.42, 251, 4, 1245, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (4, 2005, 830.57, 220, 9, 1203, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (5, 2050, 649.41, 203, 5, 1200, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (6, 2082, 695.76, 269, 2, 1200, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (7, 2145, 766.23, 256, 9, 1249, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (8, 2085, 146.58, 201, 8, 1240, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (9, 2127, 819.74, 288, 5, 1202, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (10, 2036, 803.59, 270, 9, 1208, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (11, 2138, 704.37, 223, 5, 1208, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (12, 2016, 949.56, 287, 5, 1250, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (13, 2114, 187.16, 222, 5, 1200, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (14, 2081, 545.96, 269, 3, 1217, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (15, 2084, 843.16, 247, 9, 1218, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (16, 2004, 152.79, 251, 1, 1240, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (17, 2100, 313.51, 232, 8, 1201, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (18, 2001, 34.63, 211, 10, 1232, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (19, 2072, 76.61, 247, 9, 1228, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (20, 2069, 878.9, 209, 7, 1227, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (21, 2074, 124.01, 200, 4, 1226, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (22, 2061, 429.58, 204, 3, 1212, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (23, 2027, 709.99, 300, 6, 1238, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (24, 2056, 267.88, 202, 2, 1226, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (25, 2031, 271.77, 248, 4, 1228, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (26, 2080, 397.51, 220, 10, 1200, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (27, 2006, 525.4, 207, 8, 1247, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (28, 2010, 343.29, 276, 7, 1229, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (29, 2044, 808.24, 227, 1, 1216, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (30, 2073, 451.15, 228, 3, 1231, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (31, 2074, 808.82, 296, 9, 1214, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (32, 2018, 985.56, 221, 9, 1219, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (33, 2120, 18.1, 227, 10, 1243, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (34, 2094, 532.7, 234, 1, 1238, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (35, 2018, 675.61, 212, 4, 1211, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (36, 2052, 286.88, 201, 1, 1205, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (37, 2079, 351.51, 264, 1, 1217, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (38, 2089, 834.46, 264, 3, 1200, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (39, 2111, 564.39, 288, 9, 1213, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (40, 2045, 332.85, 278, 8, 1214, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (41, 2139, 814.19, 288, 5, 1220, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (42, 2106, 645.39, 218, 4, 1207, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (43, 2082, 185.88, 230, 9, 1234, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (44, 2078, 235.07, 232, 6, 1250, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (45, 2077, 307.92, 297, 5, 1248, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (46, 2021, 606.12, 262, 1, 1203, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (47, 2028, 622.14, 296, 7, 1246, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (48, 2092, 2.41, 224, 10, 1225, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (49, 2142, 447.79, 260, 7, 1245, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (50, 2006, 970.28, 272, 8, 1202, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (51, 2078, 459.75, 274, 9, 1221, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (52, 2128, 376.82, 294, 8, 1215, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (53, 2059, 357.59, 219, 2, 1211, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (54, 2058, 535.53, 271, 8, 1246, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (55, 2127, 661.96, 227, 1, 1219, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (56, 2053, 885.07, 275, 7, 1233, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (57, 2094, 55.32, 238, 4, 1208, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (58, 2055, 420.27, 264, 2, 1238, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (59, 2117, 306.36, 222, 4, 1234, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (60, 2077, 504.6, 266, 4, 1200, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (61, 2120, 279.1, 292, 2, 1226, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (62, 2113, 904.88, 299, 1, 1241, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (63, 2051, 496.42, 249, 7, 1203, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (64, 2136, 508.71, 262, 3, 1236, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (65, 2144, 421.24, 286, 9, 1236, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (66, 2119, 236.49, 277, 5, 1241, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (67, 2030, 215.66, 216, 3, 1246, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (68, 2024, 243.15, 245, 9, 1243, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (69, 2073, 397.63, 255, 8, 1235, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (70, 2079, 163.06, 229, 4, 1201, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (71, 2070, 550.83, 289, 7, 1214, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (72, 2069, 676.38, 278, 7, 1225, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (73, 2135, 778.12, 211, 10, 1214, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (74, 2127, 563.12, 258, 9, 1223, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (75, 2010, 502.25, 214, 7, 1218, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (76, 2050, 171.66, 271, 3, 1239, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (77, 2112, 364.88, 249, 2, 1215, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (78, 2090, 821.38, 269, 1, 1239, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (79, 2079, 19.88, 228, 1, 1202, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (80, 2047, 730.79, 255, 8, 1239, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (81, 2080, 664.81, 283, 10, 1215, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (82, 2137, 340.03, 236, 4, 1214, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (83, 2092, 4.28, 203, 10, 1218, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (84, 2003, 100.14, 253, 7, 1224, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (85, 2001, 952.61, 247, 2, 1212, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (86, 2054, 773.2, 210, 8, 1224, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (87, 2037, 65.9, 291, 6, 1214, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (88, 2092, 904.74, 224, 6, 1204, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (89, 2036, 485.19, 214, 10, 1203, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (90, 2148, 946.4, 211, 2, 1236, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (91, 2045, 703.15, 232, 7, 1204, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (92, 2093, 711.61, 200, 4, 1229, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (93, 2084, 103.15, 267, 2, 1209, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (94, 2049, 202.91, 289, 1, 1245, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (95, 2038, 760.1, 243, 8, 1241, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (96, 2026, 759.33, 253, 2, 1212, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (97, 2105, 125.73, 226, 10, 1218, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (98, 2011, 176.87, 294, 10, 1213, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (99, 2120, 501.65, 204, 9, 1240, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (100, 2138, 490.44, 232, 7, 1243, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (101, 2014, 346.61, 265, 9, 1215, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (102, 2062, 176.8, 285, 5, 1235, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (103, 2112, 113.92, 224, 8, 1229, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (104, 2073, 160.8, 267, 2, 1210, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (105, 2082, 588.15, 225, 3, 1229, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (106, 2138, 571.21, 213, 1, 1242, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (107, 2092, 814.36, 213, 9, 1243, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (108, 2089, 221.8, 220, 5, 1203, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (109, 2040, 501.46, 248, 10, 1244, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (110, 2096, 974.47, 204, 6, 1221, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (111, 2078, 914.56, 208, 3, 1239, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (112, 2118, 287.53, 215, 10, 1221, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (113, 2106, 415.27, 249, 8, 1242, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (114, 2145, 283.31, 227, 6, 1231, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (115, 2148, 950.09, 243, 10, 1211, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (116, 2137, 132.57, 269, 3, 1227, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (117, 2082, 440.25, 267, 9, 1204, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (118, 2015, 749.85, 229, 8, 1232, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (119, 2021, 209.93, 229, 9, 1250, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (120, 2006, 540.63, 283, 8, 1242, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (121, 2030, 197.56, 278, 9, 1215, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (122, 2123, 153.87, 259, 5, 1239, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (123, 2079, 444.55, 259, 1, 1200, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (124, 2146, 437.87, 231, 10, 1247, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (125, 2094, 74.57, 241, 8, 1237, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (126, 2084, 660.65, 251, 3, 1237, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (127, 2085, 366.69, 209, 3, 1238, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (128, 2031, 560.65, 254, 1, 1233, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (129, 2064, 410.85, 217, 5, 1208, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (130, 2095, 241.41, 289, 10, 1243, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (131, 2106, 163.57, 235, 9, 1218, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (132, 2128, 764.88, 291, 3, 1237, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (133, 2014, 936.97, 201, 10, 1218, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (134, 2141, 351.46, 287, 1, 1202, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (135, 2094, 277.08, 218, 1, 1211, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (136, 2064, 489.19, 251, 2, 1226, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (137, 2001, 190.54, 231, 7, 1222, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (138, 2007, 252.7, 290, 8, 1242, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (139, 2058, 413.1, 214, 3, 1226, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (140, 2140, 230.58, 227, 8, 1206, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (141, 2074, 940.96, 200, 8, 1200, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (142, 2071, 618.94, 203, 9, 1250, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (143, 2002, 115.65, 213, 4, 1201, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (144, 2010, 22.85, 254, 3, 1218, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (145, 2023, 901.21, 230, 2, 1245, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (146, 2139, 173.7, 246, 8, 1202, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (147, 2047, 848.18, 225, 5, 1221, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (148, 2084, 254.96, 250, 10, 1244, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (149, 2004, 298.15, 296, 10, 1231, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (150, 2009, 413.91, 292, 9, 1245, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (151, 2009, 664.17, 277, 4, 1240, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (152, 2049, 748.86, 205, 6, 1250, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (153, 2064, 935.97, 253, 9, 1218, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (154, 2129, 577.5, 290, 9, 1237, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (155, 2052, 496.99, 211, 2, 1215, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (156, 2144, 753.54, 270, 6, 1229, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (157, 2143, 644.8, 267, 7, 1201, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (158, 2131, 710.66, 292, 8, 1217, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (159, 2051, 336.83, 229, 9, 1229, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (160, 2031, 592.09, 248, 4, 1206, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (161, 2046, 129.18, 279, 10, 1207, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (162, 2101, 536.8, 282, 7, 1204, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (163, 2112, 960.31, 296, 2, 1240, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (164, 2100, 127.35, 235, 8, 1236, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (165, 2031, 352.12, 203, 9, 1208, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (166, 2035, 110.15, 243, 10, 1229, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (167, 2105, 531.13, 234, 7, 1220, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (168, 2046, 483.93, 279, 8, 1238, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (169, 2083, 669.86, 226, 2, 1243, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (170, 2040, 373.61, 208, 10, 1223, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (171, 2060, 355.5, 220, 10, 1200, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (172, 2120, 28.3, 284, 9, 1247, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (173, 2040, 357.99, 250, 6, 1212, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (174, 2103, 980.82, 288, 2, 1202, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (175, 2035, 813.47, 217, 1, 1235, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (176, 2110, 399.64, 285, 9, 1220, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (177, 2016, 44.06, 250, 6, 1207, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (178, 2096, 66.57, 292, 4, 1214, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (179, 2030, 33.38, 239, 10, 1215, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (180, 2073, 459.77, 240, 8, 1218, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (181, 2071, 875.42, 230, 3, 1217, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (182, 2041, 380.94, 255, 3, 1247, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (183, 2097, 914.44, 298, 3, 1210, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (184, 2105, 329.25, 210, 1, 1242, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (185, 2000, 457.91, 256, 2, 1231, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (186, 2098, 901.2, 261, 10, 1249, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (187, 2146, 236.33, 293, 10, 1223, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (188, 2117, 405.01, 279, 8, 1246, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (189, 2099, 272.14, 234, 6, 1205, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (190, 2145, 42.04, 299, 8, 1204, '2023-10-26'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (191, 2017, 399.9, 280, 4, 1242, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (192, 2058, 733.45, 277, 9, 1239, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (193, 2124, 809.67, 259, 3, 1246, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (194, 2059, 167.54, 221, 10, 1233, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (195, 2032, 441.79, 219, 6, 1238, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (196, 2101, 720.37, 286, 1, 1246, '2023-10-27'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (197, 2103, 820.5, 289, 6, 1206, '2023-10-28'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (198, 2010, 433.08, 276, 9, 1213, '2023-10-29'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (199, 2147, 779.36, 237, 2, 1245, '2023-10-25'); +GO +~~ROW COUNT: 1~~ + +insert into StoreReceipt (OrderID, ItemID, Price, EmployeeID, StoreID, ManufactureID, PurchaseDate) values (200, 2084, 735.91, 223, 5, 1221, '2023-10-30'); +GO +~~ROW COUNT: 1~~ + + + +create table pivot_insert_into(ManufactureID int, EmployeeID int, p1 int, p2 int, p3 int, p4 int, p5 int); +GO + +CREATE PROCEDURE top_n_pivot + ( + @Number int = 5 + ) +AS +BEGIN + SELECT TOP(@Number) ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 + FROM + ( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt + )as srctable + PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) + ) AS pvt2 +END; +GO + +CREATE FUNCTION test_table_valued_function(@Number int) +RETURNS TABLE +AS +RETURN + SELECT TOP(@Number) ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 + FROM + ( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt + )as srctable + PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) + ) AS pvt2 +GO + +-- Cannot create view (Bug) +create view pivot_view as +SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: a column definition list is required for functions returning "record")~~ + diff --git a/test/JDBC/expected/pivot-vu-verify.out b/test/JDBC/expected/pivot-vu-verify.out new file mode 100644 index 0000000000..193299a70a --- /dev/null +++ b/test/JDBC/expected/pivot-vu-verify.out @@ -0,0 +1,1061 @@ +use pivot_test +GO + +-- 2 column in src table pivot +SELECT 'OrderNumbers' AS OrderCountbyStore, [1] AS STORE1, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5 +FROM +( + Select StoreID, OrderID + FROM StoreReceipt +)as SrcTable +PIVOT ( + COUNT (OrderID) + FOR StoreID IN ([1], [2], [3],[4], [5]) +) AS pvt +GO +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int +OrderNumbers#!#19#!#19#!#19#!#16#!#14 +~~END~~ + + +-- 3 column in src table pivot +SELECT EmployeeID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT EmployeeID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +200#!#0#!#0#!#2#!#0#!#0 +201#!#0#!#0#!#0#!#0#!#0 +202#!#1#!#0#!#0#!#0#!#0 +203#!#0#!#0#!#0#!#1#!#0 +204#!#0#!#1#!#0#!#0#!#1 +205#!#0#!#0#!#0#!#0#!#1 +207#!#0#!#0#!#0#!#0#!#0 +208#!#0#!#1#!#0#!#0#!#0 +209#!#0#!#1#!#0#!#0#!#0 +210#!#0#!#0#!#0#!#0#!#0 +211#!#2#!#0#!#0#!#0#!#0 +212#!#0#!#0#!#1#!#0#!#0 +213#!#0#!#0#!#1#!#0#!#0 +214#!#0#!#1#!#0#!#0#!#0 +215#!#0#!#0#!#0#!#0#!#0 +216#!#0#!#1#!#0#!#0#!#0 +217#!#0#!#0#!#0#!#1#!#0 +218#!#0#!#0#!#1#!#0#!#0 +219#!#1#!#0#!#0#!#0#!#1 +220#!#0#!#0#!#0#!#1#!#0 +221#!#0#!#0#!#0#!#0#!#0 +222#!#0#!#0#!#1#!#1#!#0 +223#!#0#!#0#!#0#!#2#!#0 +224#!#0#!#0#!#0#!#0#!#1 +225#!#0#!#1#!#0#!#1#!#0 +226#!#1#!#0#!#0#!#0#!#0 +227#!#0#!#0#!#0#!#0#!#1 +228#!#0#!#1#!#0#!#0#!#0 +229#!#0#!#0#!#1#!#0#!#0 +230#!#1#!#1#!#0#!#0#!#0 +231#!#0#!#0#!#0#!#0#!#0 +232#!#0#!#0#!#0#!#0#!#1 +234#!#0#!#0#!#0#!#0#!#1 +235#!#0#!#0#!#0#!#0#!#0 +236#!#0#!#0#!#1#!#0#!#0 +237#!#1#!#0#!#0#!#0#!#0 +238#!#0#!#0#!#1#!#0#!#0 +239#!#0#!#0#!#0#!#0#!#0 +240#!#0#!#0#!#0#!#0#!#0 +241#!#0#!#0#!#0#!#0#!#0 +243#!#0#!#0#!#0#!#0#!#0 +245#!#0#!#0#!#0#!#0#!#0 +246#!#0#!#0#!#0#!#0#!#0 +247#!#1#!#0#!#0#!#0#!#0 +248#!#0#!#0#!#2#!#0#!#0 +249#!#1#!#0#!#0#!#0#!#0 +250#!#0#!#0#!#0#!#0#!#2 +251#!#1#!#1#!#1#!#0#!#0 +252#!#0#!#0#!#0#!#0#!#0 +253#!#1#!#0#!#0#!#0#!#0 +254#!#0#!#1#!#0#!#0#!#0 +255#!#0#!#1#!#0#!#0#!#0 +256#!#1#!#0#!#0#!#0#!#0 +258#!#0#!#0#!#0#!#0#!#0 +259#!#0#!#1#!#0#!#1#!#0 +260#!#0#!#0#!#0#!#0#!#0 +261#!#0#!#0#!#0#!#0#!#0 +262#!#0#!#1#!#0#!#0#!#0 +264#!#1#!#1#!#0#!#0#!#0 +265#!#0#!#0#!#0#!#0#!#0 +266#!#0#!#0#!#1#!#0#!#0 +267#!#2#!#0#!#0#!#0#!#0 +269#!#1#!#2#!#0#!#0#!#0 +270#!#0#!#0#!#0#!#0#!#1 +271#!#0#!#1#!#0#!#0#!#0 +272#!#0#!#0#!#0#!#0#!#0 +274#!#0#!#0#!#0#!#0#!#0 +275#!#0#!#0#!#0#!#0#!#0 +276#!#0#!#0#!#0#!#0#!#0 +277#!#0#!#0#!#1#!#1#!#0 +278#!#0#!#0#!#0#!#0#!#0 +279#!#0#!#0#!#0#!#0#!#0 +280#!#0#!#0#!#1#!#0#!#0 +282#!#0#!#0#!#0#!#0#!#0 +283#!#0#!#0#!#0#!#0#!#0 +284#!#0#!#0#!#0#!#0#!#0 +285#!#0#!#0#!#0#!#1#!#0 +286#!#0#!#0#!#0#!#0#!#0 +287#!#0#!#0#!#0#!#1#!#0 +288#!#1#!#0#!#0#!#2#!#0 +289#!#0#!#0#!#0#!#0#!#1 +290#!#0#!#0#!#0#!#0#!#0 +291#!#0#!#1#!#0#!#0#!#1 +292#!#1#!#0#!#1#!#0#!#0 +293#!#0#!#0#!#0#!#0#!#0 +294#!#0#!#0#!#0#!#0#!#0 +296#!#1#!#0#!#0#!#0#!#0 +297#!#0#!#0#!#0#!#1#!#0 +298#!#0#!#1#!#0#!#0#!#0 +299#!#0#!#0#!#0#!#0#!#0 +300#!#0#!#0#!#0#!#0#!#1 +~~END~~ + + +-- 3+ column in src table pivot +SELECT ManufactureID, EmployeeID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, EmployeeID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int +1200#!#200#!#0#!#0#!#0#!#0#!#0 +1200#!#203#!#0#!#0#!#0#!#1#!#0 +1200#!#220#!#0#!#0#!#0#!#0#!#0 +1200#!#222#!#0#!#0#!#0#!#1#!#0 +1200#!#259#!#0#!#0#!#0#!#0#!#0 +1200#!#264#!#0#!#1#!#0#!#0#!#0 +1200#!#266#!#0#!#0#!#1#!#0#!#0 +1200#!#269#!#1#!#0#!#0#!#0#!#0 +1201#!#213#!#0#!#0#!#1#!#0#!#0 +1201#!#229#!#0#!#0#!#1#!#0#!#0 +1201#!#232#!#0#!#0#!#0#!#0#!#0 +1201#!#267#!#0#!#0#!#0#!#0#!#0 +1202#!#228#!#0#!#0#!#0#!#0#!#0 +1202#!#246#!#0#!#0#!#0#!#0#!#0 +1202#!#272#!#0#!#0#!#0#!#0#!#0 +1202#!#287#!#0#!#0#!#0#!#0#!#0 +1202#!#288#!#1#!#0#!#0#!#1#!#0 +1203#!#214#!#0#!#0#!#0#!#0#!#0 +1203#!#220#!#0#!#0#!#0#!#1#!#0 +1203#!#249#!#0#!#0#!#0#!#0#!#0 +1203#!#262#!#0#!#0#!#0#!#0#!#0 +1204#!#224#!#0#!#0#!#0#!#0#!#1 +1204#!#232#!#0#!#0#!#0#!#0#!#0 +1204#!#267#!#0#!#0#!#0#!#0#!#0 +1204#!#282#!#0#!#0#!#0#!#0#!#0 +1204#!#299#!#0#!#0#!#0#!#0#!#0 +1205#!#201#!#0#!#0#!#0#!#0#!#0 +1205#!#234#!#0#!#0#!#0#!#0#!#1 +1206#!#227#!#0#!#0#!#0#!#0#!#0 +1206#!#248#!#0#!#0#!#1#!#0#!#0 +1206#!#289#!#0#!#0#!#0#!#0#!#1 +1207#!#218#!#0#!#0#!#1#!#0#!#0 +1207#!#250#!#0#!#0#!#0#!#0#!#1 +1207#!#279#!#0#!#0#!#0#!#0#!#0 +1208#!#203#!#0#!#0#!#0#!#0#!#0 +1208#!#217#!#0#!#0#!#0#!#1#!#0 +1208#!#223#!#0#!#0#!#0#!#1#!#0 +1208#!#238#!#0#!#0#!#1#!#0#!#0 +1208#!#270#!#0#!#0#!#0#!#0#!#0 +1209#!#252#!#0#!#0#!#0#!#0#!#0 +1209#!#267#!#1#!#0#!#0#!#0#!#0 +1210#!#267#!#1#!#0#!#0#!#0#!#0 +1210#!#298#!#0#!#1#!#0#!#0#!#0 +1211#!#212#!#0#!#0#!#1#!#0#!#0 +1211#!#218#!#0#!#0#!#0#!#0#!#0 +1211#!#219#!#1#!#0#!#0#!#0#!#0 +1211#!#243#!#0#!#0#!#0#!#0#!#0 +1212#!#204#!#0#!#1#!#0#!#0#!#0 +1212#!#247#!#1#!#0#!#0#!#0#!#0 +1212#!#250#!#0#!#0#!#0#!#0#!#1 +1212#!#253#!#1#!#0#!#0#!#0#!#0 +1213#!#276#!#0#!#0#!#0#!#0#!#0 +1213#!#288#!#0#!#0#!#0#!#0#!#0 +1213#!#294#!#0#!#0#!#0#!#0#!#0 +1214#!#211#!#0#!#0#!#0#!#0#!#0 +1214#!#236#!#0#!#0#!#1#!#0#!#0 +1214#!#278#!#0#!#0#!#0#!#0#!#0 +1214#!#289#!#0#!#0#!#0#!#0#!#0 +1214#!#291#!#0#!#0#!#0#!#0#!#1 +1214#!#292#!#0#!#0#!#1#!#0#!#0 +1214#!#296#!#0#!#0#!#0#!#0#!#0 +1215#!#211#!#1#!#0#!#0#!#0#!#0 +1215#!#239#!#0#!#0#!#0#!#0#!#0 +1215#!#249#!#1#!#0#!#0#!#0#!#0 +1215#!#265#!#0#!#0#!#0#!#0#!#0 +1215#!#278#!#0#!#0#!#0#!#0#!#0 +1215#!#283#!#0#!#0#!#0#!#0#!#0 +1215#!#294#!#0#!#0#!#0#!#0#!#0 +1216#!#227#!#0#!#0#!#0#!#0#!#0 +1217#!#230#!#0#!#1#!#0#!#0#!#0 +1217#!#264#!#0#!#0#!#0#!#0#!#0 +1217#!#269#!#0#!#1#!#0#!#0#!#0 +1217#!#292#!#0#!#0#!#0#!#0#!#0 +1218#!#201#!#0#!#0#!#0#!#0#!#0 +1218#!#203#!#0#!#0#!#0#!#0#!#0 +1218#!#214#!#0#!#0#!#0#!#0#!#0 +1218#!#226#!#0#!#0#!#0#!#0#!#0 +1218#!#235#!#0#!#0#!#0#!#0#!#0 +1218#!#240#!#0#!#0#!#0#!#0#!#0 +1218#!#247#!#0#!#0#!#0#!#0#!#0 +1218#!#253#!#0#!#0#!#0#!#0#!#0 +1218#!#254#!#0#!#1#!#0#!#0#!#0 +1219#!#221#!#0#!#0#!#0#!#0#!#0 +1219#!#227#!#0#!#0#!#0#!#0#!#0 +1220#!#234#!#0#!#0#!#0#!#0#!#0 +1220#!#285#!#0#!#0#!#0#!#0#!#0 +1220#!#288#!#0#!#0#!#0#!#1#!#0 +1221#!#204#!#0#!#0#!#0#!#0#!#1 +1221#!#215#!#0#!#0#!#0#!#0#!#0 +1221#!#223#!#0#!#0#!#0#!#1#!#0 +1221#!#225#!#0#!#0#!#0#!#1#!#0 +1221#!#274#!#0#!#0#!#0#!#0#!#0 +1222#!#231#!#0#!#0#!#0#!#0#!#0 +1223#!#208#!#0#!#0#!#0#!#0#!#0 +1223#!#258#!#0#!#0#!#0#!#0#!#0 +1223#!#293#!#0#!#0#!#0#!#0#!#0 +1224#!#210#!#0#!#0#!#0#!#0#!#0 +1224#!#253#!#0#!#0#!#0#!#0#!#0 +1225#!#224#!#0#!#0#!#0#!#0#!#0 +1225#!#278#!#0#!#0#!#0#!#0#!#0 +1226#!#200#!#0#!#0#!#1#!#0#!#0 +1226#!#202#!#1#!#0#!#0#!#0#!#0 +1226#!#214#!#0#!#1#!#0#!#0#!#0 +1226#!#251#!#1#!#0#!#0#!#0#!#0 +1226#!#292#!#1#!#0#!#0#!#0#!#0 +1227#!#209#!#0#!#0#!#0#!#0#!#0 +1227#!#269#!#0#!#1#!#0#!#0#!#0 +1228#!#247#!#0#!#0#!#0#!#0#!#0 +1228#!#248#!#0#!#0#!#1#!#0#!#0 +1229#!#200#!#0#!#0#!#1#!#0#!#0 +1229#!#224#!#0#!#0#!#0#!#0#!#0 +1229#!#225#!#0#!#1#!#0#!#0#!#0 +1229#!#229#!#0#!#0#!#0#!#0#!#0 +1229#!#243#!#0#!#0#!#0#!#0#!#0 +1229#!#270#!#0#!#0#!#0#!#0#!#1 +1229#!#276#!#0#!#0#!#0#!#0#!#0 +1231#!#227#!#0#!#0#!#0#!#0#!#1 +1231#!#228#!#0#!#1#!#0#!#0#!#0 +1231#!#256#!#1#!#0#!#0#!#0#!#0 +1231#!#296#!#0#!#0#!#0#!#0#!#0 +1232#!#211#!#0#!#0#!#0#!#0#!#0 +1232#!#229#!#0#!#0#!#0#!#0#!#0 +1233#!#221#!#0#!#0#!#0#!#0#!#0 +1233#!#254#!#0#!#0#!#0#!#0#!#0 +1233#!#275#!#0#!#0#!#0#!#0#!#0 +1234#!#222#!#0#!#0#!#1#!#0#!#0 +1234#!#230#!#0#!#0#!#0#!#0#!#0 +1234#!#296#!#0#!#0#!#0#!#0#!#0 +1235#!#217#!#0#!#0#!#0#!#0#!#0 +1235#!#255#!#0#!#0#!#0#!#0#!#0 +1235#!#285#!#0#!#0#!#0#!#1#!#0 +1236#!#211#!#1#!#0#!#0#!#0#!#0 +1236#!#235#!#0#!#0#!#0#!#0#!#0 +1236#!#262#!#0#!#1#!#0#!#0#!#0 +1236#!#286#!#0#!#0#!#0#!#0#!#0 +1237#!#241#!#0#!#0#!#0#!#0#!#0 +1237#!#251#!#0#!#1#!#0#!#0#!#0 +1237#!#290#!#0#!#0#!#0#!#0#!#0 +1237#!#291#!#0#!#1#!#0#!#0#!#0 +1238#!#209#!#0#!#1#!#0#!#0#!#0 +1238#!#219#!#0#!#0#!#0#!#0#!#1 +1238#!#234#!#0#!#0#!#0#!#0#!#0 +1238#!#264#!#1#!#0#!#0#!#0#!#0 +1238#!#279#!#0#!#0#!#0#!#0#!#0 +1238#!#300#!#0#!#0#!#0#!#0#!#1 +1239#!#208#!#0#!#1#!#0#!#0#!#0 +1239#!#255#!#0#!#0#!#0#!#0#!#0 +1239#!#259#!#0#!#0#!#0#!#1#!#0 +1239#!#269#!#0#!#0#!#0#!#0#!#0 +1239#!#271#!#0#!#1#!#0#!#0#!#0 +1239#!#277#!#0#!#0#!#0#!#0#!#0 +1240#!#201#!#0#!#0#!#0#!#0#!#0 +1240#!#204#!#0#!#0#!#0#!#0#!#0 +1240#!#251#!#0#!#0#!#0#!#0#!#0 +1240#!#277#!#0#!#0#!#1#!#0#!#0 +1240#!#296#!#1#!#0#!#0#!#0#!#0 +1241#!#243#!#0#!#0#!#0#!#0#!#0 +1241#!#277#!#0#!#0#!#0#!#1#!#0 +1241#!#299#!#0#!#0#!#0#!#0#!#0 +1242#!#210#!#0#!#0#!#0#!#0#!#0 +1242#!#213#!#0#!#0#!#0#!#0#!#0 +1242#!#249#!#0#!#0#!#0#!#0#!#0 +1242#!#280#!#0#!#0#!#1#!#0#!#0 +1242#!#283#!#0#!#0#!#0#!#0#!#0 +1242#!#290#!#0#!#0#!#0#!#0#!#0 +1243#!#213#!#0#!#0#!#0#!#0#!#0 +1243#!#226#!#1#!#0#!#0#!#0#!#0 +1243#!#227#!#0#!#0#!#0#!#0#!#0 +1243#!#232#!#0#!#0#!#0#!#0#!#0 +1243#!#245#!#0#!#0#!#0#!#0#!#0 +1243#!#289#!#0#!#0#!#0#!#0#!#0 +1244#!#248#!#0#!#0#!#0#!#0#!#0 +1244#!#250#!#0#!#0#!#0#!#0#!#0 +1245#!#230#!#1#!#0#!#0#!#0#!#0 +1245#!#237#!#1#!#0#!#0#!#0#!#0 +1245#!#251#!#0#!#0#!#1#!#0#!#0 +1245#!#260#!#0#!#0#!#0#!#0#!#0 +1245#!#289#!#0#!#0#!#0#!#0#!#0 +1245#!#292#!#0#!#0#!#0#!#0#!#0 +1246#!#216#!#0#!#1#!#0#!#0#!#0 +1246#!#259#!#0#!#1#!#0#!#0#!#0 +1246#!#271#!#0#!#0#!#0#!#0#!#0 +1246#!#279#!#0#!#0#!#0#!#0#!#0 +1246#!#286#!#0#!#0#!#0#!#0#!#0 +1246#!#296#!#0#!#0#!#0#!#0#!#0 +1247#!#207#!#0#!#0#!#0#!#0#!#0 +1247#!#231#!#0#!#0#!#0#!#0#!#0 +1247#!#255#!#0#!#1#!#0#!#0#!#0 +1247#!#284#!#0#!#0#!#0#!#0#!#0 +1248#!#297#!#0#!#0#!#0#!#1#!#0 +1249#!#256#!#0#!#0#!#0#!#0#!#0 +1249#!#261#!#0#!#0#!#0#!#0#!#0 +1250#!#203#!#0#!#0#!#0#!#0#!#0 +1250#!#205#!#0#!#0#!#0#!#0#!#1 +1250#!#229#!#0#!#0#!#0#!#0#!#0 +1250#!#232#!#0#!#0#!#0#!#0#!#1 +1250#!#287#!#0#!#0#!#0#!#1#!#0 +~~END~~ + + +-- order by test +SELECT ManufactureID, EmployeeID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, EmployeeID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +order by EmployeeID +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int +1226#!#200#!#0#!#0#!#1#!#0#!#0 +1229#!#200#!#0#!#0#!#1#!#0#!#0 +1200#!#200#!#0#!#0#!#0#!#0#!#0 +1218#!#201#!#0#!#0#!#0#!#0#!#0 +1240#!#201#!#0#!#0#!#0#!#0#!#0 +1205#!#201#!#0#!#0#!#0#!#0#!#0 +1226#!#202#!#1#!#0#!#0#!#0#!#0 +1200#!#203#!#0#!#0#!#0#!#1#!#0 +1250#!#203#!#0#!#0#!#0#!#0#!#0 +1208#!#203#!#0#!#0#!#0#!#0#!#0 +1218#!#203#!#0#!#0#!#0#!#0#!#0 +1212#!#204#!#0#!#1#!#0#!#0#!#0 +1221#!#204#!#0#!#0#!#0#!#0#!#1 +1240#!#204#!#0#!#0#!#0#!#0#!#0 +1250#!#205#!#0#!#0#!#0#!#0#!#1 +1247#!#207#!#0#!#0#!#0#!#0#!#0 +1239#!#208#!#0#!#1#!#0#!#0#!#0 +1223#!#208#!#0#!#0#!#0#!#0#!#0 +1227#!#209#!#0#!#0#!#0#!#0#!#0 +1238#!#209#!#0#!#1#!#0#!#0#!#0 +1224#!#210#!#0#!#0#!#0#!#0#!#0 +1242#!#210#!#0#!#0#!#0#!#0#!#0 +1214#!#211#!#0#!#0#!#0#!#0#!#0 +1236#!#211#!#1#!#0#!#0#!#0#!#0 +1215#!#211#!#1#!#0#!#0#!#0#!#0 +1232#!#211#!#0#!#0#!#0#!#0#!#0 +1211#!#212#!#0#!#0#!#1#!#0#!#0 +1243#!#213#!#0#!#0#!#0#!#0#!#0 +1201#!#213#!#0#!#0#!#1#!#0#!#0 +1242#!#213#!#0#!#0#!#0#!#0#!#0 +1203#!#214#!#0#!#0#!#0#!#0#!#0 +1226#!#214#!#0#!#1#!#0#!#0#!#0 +1218#!#214#!#0#!#0#!#0#!#0#!#0 +1221#!#215#!#0#!#0#!#0#!#0#!#0 +1246#!#216#!#0#!#1#!#0#!#0#!#0 +1235#!#217#!#0#!#0#!#0#!#0#!#0 +1208#!#217#!#0#!#0#!#0#!#1#!#0 +1211#!#218#!#0#!#0#!#0#!#0#!#0 +1207#!#218#!#0#!#0#!#1#!#0#!#0 +1238#!#219#!#0#!#0#!#0#!#0#!#1 +1211#!#219#!#1#!#0#!#0#!#0#!#0 +1203#!#220#!#0#!#0#!#0#!#1#!#0 +1200#!#220#!#0#!#0#!#0#!#0#!#0 +1233#!#221#!#0#!#0#!#0#!#0#!#0 +1219#!#221#!#0#!#0#!#0#!#0#!#0 +1234#!#222#!#0#!#0#!#1#!#0#!#0 +1200#!#222#!#0#!#0#!#0#!#1#!#0 +1208#!#223#!#0#!#0#!#0#!#1#!#0 +1221#!#223#!#0#!#0#!#0#!#1#!#0 +1225#!#224#!#0#!#0#!#0#!#0#!#0 +1204#!#224#!#0#!#0#!#0#!#0#!#1 +1229#!#224#!#0#!#0#!#0#!#0#!#0 +1221#!#225#!#0#!#0#!#0#!#1#!#0 +1229#!#225#!#0#!#1#!#0#!#0#!#0 +1243#!#226#!#1#!#0#!#0#!#0#!#0 +1218#!#226#!#0#!#0#!#0#!#0#!#0 +1206#!#227#!#0#!#0#!#0#!#0#!#0 +1216#!#227#!#0#!#0#!#0#!#0#!#0 +1231#!#227#!#0#!#0#!#0#!#0#!#1 +1243#!#227#!#0#!#0#!#0#!#0#!#0 +1219#!#227#!#0#!#0#!#0#!#0#!#0 +1202#!#228#!#0#!#0#!#0#!#0#!#0 +1231#!#228#!#0#!#1#!#0#!#0#!#0 +1229#!#229#!#0#!#0#!#0#!#0#!#0 +1201#!#229#!#0#!#0#!#1#!#0#!#0 +1250#!#229#!#0#!#0#!#0#!#0#!#0 +1232#!#229#!#0#!#0#!#0#!#0#!#0 +1217#!#230#!#0#!#1#!#0#!#0#!#0 +1234#!#230#!#0#!#0#!#0#!#0#!#0 +1245#!#230#!#1#!#0#!#0#!#0#!#0 +1247#!#231#!#0#!#0#!#0#!#0#!#0 +1222#!#231#!#0#!#0#!#0#!#0#!#0 +1204#!#232#!#0#!#0#!#0#!#0#!#0 +1243#!#232#!#0#!#0#!#0#!#0#!#0 +1201#!#232#!#0#!#0#!#0#!#0#!#0 +1250#!#232#!#0#!#0#!#0#!#0#!#1 +1220#!#234#!#0#!#0#!#0#!#0#!#0 +1238#!#234#!#0#!#0#!#0#!#0#!#0 +1205#!#234#!#0#!#0#!#0#!#0#!#1 +1236#!#235#!#0#!#0#!#0#!#0#!#0 +1218#!#235#!#0#!#0#!#0#!#0#!#0 +1214#!#236#!#0#!#0#!#1#!#0#!#0 +1245#!#237#!#1#!#0#!#0#!#0#!#0 +1208#!#238#!#0#!#0#!#1#!#0#!#0 +1215#!#239#!#0#!#0#!#0#!#0#!#0 +1218#!#240#!#0#!#0#!#0#!#0#!#0 +1237#!#241#!#0#!#0#!#0#!#0#!#0 +1211#!#243#!#0#!#0#!#0#!#0#!#0 +1241#!#243#!#0#!#0#!#0#!#0#!#0 +1229#!#243#!#0#!#0#!#0#!#0#!#0 +1243#!#245#!#0#!#0#!#0#!#0#!#0 +1202#!#246#!#0#!#0#!#0#!#0#!#0 +1212#!#247#!#1#!#0#!#0#!#0#!#0 +1218#!#247#!#0#!#0#!#0#!#0#!#0 +1228#!#247#!#0#!#0#!#0#!#0#!#0 +1228#!#248#!#0#!#0#!#1#!#0#!#0 +1244#!#248#!#0#!#0#!#0#!#0#!#0 +1206#!#248#!#0#!#0#!#1#!#0#!#0 +1215#!#249#!#1#!#0#!#0#!#0#!#0 +1242#!#249#!#0#!#0#!#0#!#0#!#0 +1203#!#249#!#0#!#0#!#0#!#0#!#0 +1212#!#250#!#0#!#0#!#0#!#0#!#1 +1244#!#250#!#0#!#0#!#0#!#0#!#0 +1207#!#250#!#0#!#0#!#0#!#0#!#1 +1240#!#251#!#0#!#0#!#0#!#0#!#0 +1226#!#251#!#1#!#0#!#0#!#0#!#0 +1245#!#251#!#0#!#0#!#1#!#0#!#0 +1237#!#251#!#0#!#1#!#0#!#0#!#0 +1209#!#252#!#0#!#0#!#0#!#0#!#0 +1218#!#253#!#0#!#0#!#0#!#0#!#0 +1212#!#253#!#1#!#0#!#0#!#0#!#0 +1224#!#253#!#0#!#0#!#0#!#0#!#0 +1233#!#254#!#0#!#0#!#0#!#0#!#0 +1218#!#254#!#0#!#1#!#0#!#0#!#0 +1247#!#255#!#0#!#1#!#0#!#0#!#0 +1235#!#255#!#0#!#0#!#0#!#0#!#0 +1239#!#255#!#0#!#0#!#0#!#0#!#0 +1249#!#256#!#0#!#0#!#0#!#0#!#0 +1231#!#256#!#1#!#0#!#0#!#0#!#0 +1223#!#258#!#0#!#0#!#0#!#0#!#0 +1246#!#259#!#0#!#1#!#0#!#0#!#0 +1200#!#259#!#0#!#0#!#0#!#0#!#0 +1239#!#259#!#0#!#0#!#0#!#1#!#0 +1245#!#260#!#0#!#0#!#0#!#0#!#0 +1249#!#261#!#0#!#0#!#0#!#0#!#0 +1203#!#262#!#0#!#0#!#0#!#0#!#0 +1236#!#262#!#0#!#1#!#0#!#0#!#0 +1200#!#264#!#0#!#1#!#0#!#0#!#0 +1238#!#264#!#1#!#0#!#0#!#0#!#0 +1217#!#264#!#0#!#0#!#0#!#0#!#0 +1215#!#265#!#0#!#0#!#0#!#0#!#0 +1200#!#266#!#0#!#0#!#1#!#0#!#0 +1210#!#267#!#1#!#0#!#0#!#0#!#0 +1201#!#267#!#0#!#0#!#0#!#0#!#0 +1209#!#267#!#1#!#0#!#0#!#0#!#0 +1204#!#267#!#0#!#0#!#0#!#0#!#0 +1239#!#269#!#0#!#0#!#0#!#0#!#0 +1200#!#269#!#1#!#0#!#0#!#0#!#0 +1217#!#269#!#0#!#1#!#0#!#0#!#0 +1227#!#269#!#0#!#1#!#0#!#0#!#0 +1208#!#270#!#0#!#0#!#0#!#0#!#0 +1229#!#270#!#0#!#0#!#0#!#0#!#1 +1246#!#271#!#0#!#0#!#0#!#0#!#0 +1239#!#271#!#0#!#1#!#0#!#0#!#0 +1202#!#272#!#0#!#0#!#0#!#0#!#0 +1221#!#274#!#0#!#0#!#0#!#0#!#0 +1233#!#275#!#0#!#0#!#0#!#0#!#0 +1229#!#276#!#0#!#0#!#0#!#0#!#0 +1213#!#276#!#0#!#0#!#0#!#0#!#0 +1240#!#277#!#0#!#0#!#1#!#0#!#0 +1239#!#277#!#0#!#0#!#0#!#0#!#0 +1241#!#277#!#0#!#0#!#0#!#1#!#0 +1225#!#278#!#0#!#0#!#0#!#0#!#0 +1215#!#278#!#0#!#0#!#0#!#0#!#0 +1214#!#278#!#0#!#0#!#0#!#0#!#0 +1207#!#279#!#0#!#0#!#0#!#0#!#0 +1246#!#279#!#0#!#0#!#0#!#0#!#0 +1238#!#279#!#0#!#0#!#0#!#0#!#0 +1242#!#280#!#0#!#0#!#1#!#0#!#0 +1204#!#282#!#0#!#0#!#0#!#0#!#0 +1242#!#283#!#0#!#0#!#0#!#0#!#0 +1215#!#283#!#0#!#0#!#0#!#0#!#0 +1247#!#284#!#0#!#0#!#0#!#0#!#0 +1220#!#285#!#0#!#0#!#0#!#0#!#0 +1235#!#285#!#0#!#0#!#0#!#1#!#0 +1236#!#286#!#0#!#0#!#0#!#0#!#0 +1246#!#286#!#0#!#0#!#0#!#0#!#0 +1250#!#287#!#0#!#0#!#0#!#1#!#0 +1202#!#287#!#0#!#0#!#0#!#0#!#0 +1202#!#288#!#1#!#0#!#0#!#1#!#0 +1220#!#288#!#0#!#0#!#0#!#1#!#0 +1213#!#288#!#0#!#0#!#0#!#0#!#0 +1245#!#289#!#0#!#0#!#0#!#0#!#0 +1206#!#289#!#0#!#0#!#0#!#0#!#1 +1243#!#289#!#0#!#0#!#0#!#0#!#0 +1214#!#289#!#0#!#0#!#0#!#0#!#0 +1237#!#290#!#0#!#0#!#0#!#0#!#0 +1242#!#290#!#0#!#0#!#0#!#0#!#0 +1214#!#291#!#0#!#0#!#0#!#0#!#1 +1237#!#291#!#0#!#1#!#0#!#0#!#0 +1245#!#292#!#0#!#0#!#0#!#0#!#0 +1226#!#292#!#1#!#0#!#0#!#0#!#0 +1217#!#292#!#0#!#0#!#0#!#0#!#0 +1214#!#292#!#0#!#0#!#1#!#0#!#0 +1223#!#293#!#0#!#0#!#0#!#0#!#0 +1213#!#294#!#0#!#0#!#0#!#0#!#0 +1215#!#294#!#0#!#0#!#0#!#0#!#0 +1246#!#296#!#0#!#0#!#0#!#0#!#0 +1214#!#296#!#0#!#0#!#0#!#0#!#0 +1231#!#296#!#0#!#0#!#0#!#0#!#0 +1240#!#296#!#1#!#0#!#0#!#0#!#0 +1234#!#296#!#0#!#0#!#0#!#0#!#0 +1248#!#297#!#0#!#0#!#0#!#1#!#0 +1210#!#298#!#0#!#1#!#0#!#0#!#0 +1204#!#299#!#0#!#0#!#0#!#0#!#0 +1241#!#299#!#0#!#0#!#0#!#0#!#0 +1238#!#300#!#0#!#0#!#0#!#0#!#1 +~~END~~ + + +-- whereclause test +SELECT ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +where ManufactureID < 1220 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +1205#!#0#!#0#!#0#!#0#!#1 +1206#!#0#!#0#!#1#!#0#!#1 +1207#!#0#!#0#!#1#!#0#!#1 +1208#!#0#!#0#!#1#!#2#!#0 +1209#!#1#!#0#!#0#!#0#!#0 +1210#!#1#!#1#!#0#!#0#!#0 +1211#!#1#!#0#!#1#!#0#!#0 +1212#!#2#!#1#!#0#!#0#!#1 +1213#!#0#!#0#!#0#!#0#!#0 +1214#!#0#!#0#!#2#!#0#!#1 +1215#!#2#!#0#!#0#!#0#!#0 +1216#!#0#!#0#!#0#!#0#!#0 +1217#!#0#!#2#!#0#!#0#!#0 +1218#!#0#!#1#!#0#!#0#!#0 +1219#!#0#!#0#!#0#!#0#!#0 +~~END~~ + + +-- groupby, having clause test +SELECT EmployeeID, ManufactureID, [2] as STORE2 +FROM +( + SELECT EmployeeID, ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +where EmployeeID < 210 +group by EmployeeID, ManufactureID, [2] +having ManufactureID < 1250 +order by 1,2 +GO +~~START~~ +int#!#int#!#int +200#!#1200#!#0 +200#!#1226#!#0 +200#!#1229#!#0 +201#!#1205#!#0 +201#!#1218#!#0 +201#!#1240#!#0 +202#!#1226#!#1 +203#!#1200#!#0 +203#!#1208#!#0 +203#!#1218#!#0 +204#!#1212#!#0 +204#!#1221#!#0 +204#!#1240#!#0 +207#!#1247#!#0 +208#!#1223#!#0 +208#!#1239#!#0 +209#!#1227#!#0 +209#!#1238#!#0 +~~END~~ + + + +-- top test +SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +~~END~~ + + +-- distinct test +SELECT distinct ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +1205#!#0#!#0#!#0#!#0#!#1 +1206#!#0#!#0#!#1#!#0#!#1 +1207#!#0#!#0#!#1#!#0#!#1 +1208#!#0#!#0#!#1#!#2#!#0 +1209#!#1#!#0#!#0#!#0#!#0 +1210#!#1#!#1#!#0#!#0#!#0 +1211#!#1#!#0#!#1#!#0#!#0 +1212#!#2#!#1#!#0#!#0#!#1 +1213#!#0#!#0#!#0#!#0#!#0 +1214#!#0#!#0#!#2#!#0#!#1 +1215#!#2#!#0#!#0#!#0#!#0 +1216#!#0#!#0#!#0#!#0#!#0 +1217#!#0#!#2#!#0#!#0#!#0 +1218#!#0#!#1#!#0#!#0#!#0 +1219#!#0#!#0#!#0#!#0#!#0 +1220#!#0#!#0#!#0#!#1#!#0 +1221#!#0#!#0#!#0#!#2#!#1 +1222#!#0#!#0#!#0#!#0#!#0 +1223#!#0#!#0#!#0#!#0#!#0 +1224#!#0#!#0#!#0#!#0#!#0 +1225#!#0#!#0#!#0#!#0#!#0 +1226#!#3#!#1#!#1#!#0#!#0 +1227#!#0#!#1#!#0#!#0#!#0 +1228#!#0#!#0#!#1#!#0#!#0 +1229#!#0#!#1#!#1#!#0#!#1 +1231#!#1#!#1#!#0#!#0#!#1 +1232#!#0#!#0#!#0#!#0#!#0 +1233#!#0#!#0#!#0#!#0#!#0 +1234#!#0#!#0#!#1#!#0#!#0 +1235#!#0#!#0#!#0#!#1#!#0 +1236#!#1#!#1#!#0#!#0#!#0 +1237#!#0#!#2#!#0#!#0#!#0 +1238#!#1#!#1#!#0#!#0#!#2 +1239#!#0#!#2#!#0#!#1#!#0 +1240#!#1#!#0#!#1#!#0#!#0 +1241#!#0#!#0#!#0#!#1#!#0 +1242#!#0#!#0#!#1#!#0#!#0 +1243#!#1#!#0#!#0#!#0#!#0 +1244#!#0#!#0#!#0#!#0#!#0 +1245#!#2#!#0#!#1#!#0#!#0 +1246#!#0#!#2#!#0#!#0#!#0 +1247#!#0#!#1#!#0#!#0#!#0 +1248#!#0#!#0#!#0#!#1#!#0 +1249#!#0#!#0#!#0#!#0#!#0 +1250#!#0#!#0#!#0#!#1#!#2 +~~END~~ + + + +-- insert into test +INSERT INTO pivot_insert_into +SELECT ManufactureID, EmployeeID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, EmployeeID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt; +SELECT TOP 10 * FROM pivot_insert_into order by 1, 2; +GO +~~ROW COUNT: 197~~ + +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int +1200#!#200#!#0#!#0#!#0#!#0#!#0 +1200#!#203#!#0#!#0#!#0#!#1#!#0 +1200#!#220#!#0#!#0#!#0#!#0#!#0 +1200#!#222#!#0#!#0#!#0#!#1#!#0 +1200#!#259#!#0#!#0#!#0#!#0#!#0 +1200#!#264#!#0#!#1#!#0#!#0#!#0 +1200#!#266#!#0#!#0#!#1#!#0#!#0 +1200#!#269#!#1#!#0#!#0#!#0#!#0 +1201#!#213#!#0#!#0#!#1#!#0#!#0 +1201#!#229#!#0#!#0#!#1#!#0#!#0 +~~END~~ + + + +-- select into test +SELECT ManufactureID, EmployeeID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +INTO pivot_select_into +FROM +( + SELECT ManufactureID, EmployeeID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt; +SELECT TOP 10 * FROM pivot_select_into order by 1, 2; +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int#!#int +1200#!#200#!#0#!#0#!#0#!#0#!#0 +1200#!#203#!#0#!#0#!#0#!#1#!#0 +1200#!#220#!#0#!#0#!#0#!#0#!#0 +1200#!#222#!#0#!#0#!#0#!#1#!#0 +1200#!#259#!#0#!#0#!#0#!#0#!#0 +1200#!#264#!#0#!#1#!#0#!#0#!#0 +1200#!#266#!#0#!#0#!#1#!#0#!#0 +1200#!#269#!#1#!#0#!#0#!#0#!#0 +1201#!#213#!#0#!#0#!#1#!#0#!#0 +1201#!#229#!#0#!#0#!#1#!#0#!#0 +~~END~~ + + +-- union test +SELECT TOP 5 EmployeeID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT EmployeeID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +UNION +SELECT TOP 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt2 +order by 1 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +200#!#0#!#0#!#2#!#0#!#0 +201#!#0#!#0#!#0#!#0#!#0 +202#!#1#!#0#!#0#!#0#!#0 +203#!#0#!#0#!#0#!#1#!#0 +204#!#0#!#1#!#0#!#0#!#1 +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +~~END~~ + + +-- sub query test +SELECT TOP 3 * from ( + SELECT ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 + FROM + ( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt + )as srctable + PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) + ) AS pvt2 +) p +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +~~END~~ + + +-- table variable test +DECLARE @pivot_table_var TABLE ( + ManufactureID INT, + ItemID INT, + StoreID INT +); +INSERT INTO @pivot_table_var SELECT ManufactureID, ItemID, StoreID FROM StoreReceipt; +SELECT TOP 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM + @pivot_table_var +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt2 +GO +~~ROW COUNT: 200~~ + +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +~~END~~ + + +-- temp table test +SELECT ManufactureID, ItemID, StoreID into #pivot_temp_table FROM StoreReceipt; +SELECT TOP 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM + #pivot_temp_table +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt2 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +~~END~~ + + +-- procedure test +-- Cannot execute twice (BUG) +exec top_n_pivot 10 +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +1205#!#0#!#0#!#0#!#0#!#1 +1206#!#0#!#0#!#1#!#0#!#1 +1207#!#0#!#0#!#1#!#0#!#1 +1208#!#0#!#0#!#1#!#2#!#0 +1209#!#1#!#0#!#0#!#0#!#0 +~~END~~ + + +-- function test +-- Cannot execute twice (BUG) +select * from test_table_valued_function(12); +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#1#!#1#!#1#!#2#!#0 +1201#!#0#!#0#!#2#!#0#!#0 +1202#!#1#!#0#!#0#!#1#!#0 +1203#!#0#!#0#!#0#!#1#!#0 +1204#!#0#!#0#!#0#!#0#!#1 +1205#!#0#!#0#!#0#!#0#!#1 +1206#!#0#!#0#!#1#!#0#!#1 +1207#!#0#!#0#!#1#!#0#!#1 +1208#!#0#!#0#!#1#!#2#!#0 +1209#!#1#!#0#!#0#!#0#!#0 +1210#!#1#!#1#!#0#!#0#!#0 +1211#!#1#!#0#!#1#!#0#!#0 +~~END~~ + + +-- explain pivot +set BABELFISH_SHOWPLAN_ALL ON; +SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~START~~ +text +Query Text: SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +Limit (cost=0.00..0.05 rows=5 width=24) + -> Function Scan on bbf_pivot pvt (cost=0.00..10.00 rows=1000 width=24) +~~END~~ + +set BABELFISH_SHOWPLAN_ALL OFF; +GO + + +-- test column name with indirection (value column) +SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (srctable.ItemID) + FOR StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#0#!#0#!#0#!#1#!#0 +1200#!#0#!#0#!#0#!#0#!#0 +1200#!#0#!#0#!#0#!#0#!#0 +1200#!#0#!#0#!#1#!#0#!#0 +1200#!#0#!#0#!#0#!#0#!#0 +~~END~~ + + +-- test column name win indirection (category column) +SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3, [4] AS STORE4, [5] AS STORE5, [6] AS STORE6 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (ItemID) + FOR srctable.StoreID in ([2], [3], [4], [5], [6]) +) AS pvt +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error at or near ".")~~ + + +-- left join test +-- Wrong result (bug) +Select * from (SELECT top 5 ManufactureID, [2] AS STORE2, [3] AS STORE3 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (srctable.ItemID) + FOR StoreID in ([2], [3]) +) AS pvt) as p1 +left outer join +(SELECT top 5 ManufactureID, [4] AS STORE2, [5] AS STORE3 +FROM +( + SELECT ManufactureID, ItemID, StoreID + FROM StoreReceipt +)as srctable +PIVOT ( + COUNT (srctable.ItemID) + FOR StoreID in ([4], [5]) +) AS pvt2) as p2 +on p1.ManufactureID = p2.ManufactureID +GO +~~START~~ +int#!#int#!#int#!#int#!#int#!#int +1200#!#0#!#1#!#1200#!#0#!#0 +1200#!#0#!#1#!#1200#!#0#!#0 +1200#!#0#!#1#!#1200#!#0#!#0 +1200#!#0#!#1#!#1200#!#0#!#0 +1200#!#0#!#1#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#1#!#0#!#1200#!#0#!#0 +1200#!#1#!#0#!#1200#!#0#!#0 +1200#!#1#!#0#!#1200#!#0#!#0 +1200#!#1#!#0#!#1200#!#0#!#0 +1200#!#1#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +1200#!#0#!#0#!#1200#!#0#!#0 +~~END~~ + diff --git a/test/JDBC/expected/psql_logical_babelfish_db.out b/test/JDBC/expected/psql_logical_babelfish_db.out new file mode 100644 index 0000000000..0a804f271d --- /dev/null +++ b/test/JDBC/expected/psql_logical_babelfish_db.out @@ -0,0 +1,207 @@ +-- psql +-- check whether we can query system views before setting the GUC. Should return zero rows +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases'; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar"#!#varchar#!#"sys"."varchar"#!#int4#!#int4#!#int2#!#int2#!#int4#!#int2#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar" +~~END~~ + + +-- GUC should be NULL as it is not set yet +show psql_logical_babelfish_db_name; +go +~~START~~ +text + +~~END~~ + + +-- set the GUC to master +set psql_logical_babelfish_db_name = 'master'; +go + +-- check whether the GUC has been set to master +show psql_logical_babelfish_db_name; +go +~~START~~ +text +master +~~END~~ + + +-- query system views. Should return metadata of master database +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases'; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar"#!#varchar#!#"sys"."varchar"#!#int4#!#int4#!#int2#!#int2#!#int4#!#int2#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar" +master#!#dbo#!#sysdatabases#!#name#!#1#!##!#YES#!#text#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!#C#!##!##!# +master#!#dbo#!#sysdatabases#!#dbid#!#2#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#sid#!#3#!##!#YES#!#varbinary#!#85#!#85#!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#mode#!#4#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#status#!#5#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#status2#!#6#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#crdate#!#7#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#reserved#!#8#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#category#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#cmptlevel#!#10#!##!#YES#!#tinyint#!##!##!#3#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#filename#!#11#!##!#YES#!#nvarchar#!#260#!#520#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#sysdatabases#!#version#!#12#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +~~END~~ + + +-- set the GUC to an invalid database +set psql_logical_babelfish_db_name = 'invalid_db' +go + +-- should return zero rows as the database set does not exist +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases'; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar"#!#varchar#!#"sys"."varchar"#!#int4#!#int4#!#int2#!#int2#!#int4#!#int2#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar" +~~END~~ + + +-- tsql +-- should return data of master as the current database is master +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases' +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#!#sysdatabases#!#name#!#1#!##!#YES#!#text#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!#C#!##!##!# +master#!#dbo#!#sysdatabases#!#dbid#!#2#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#sid#!#3#!##!#YES#!#varbinary#!#85#!#85#!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#mode#!#4#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#status#!#5#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#status2#!#6#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#crdate#!#7#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#reserved#!#8#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#category#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#cmptlevel#!#10#!##!#YES#!#tinyint#!##!##!#3#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#filename#!#11#!##!#YES#!#nvarchar#!#260#!#520#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#sysdatabases#!#version#!#12#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +~~END~~ + + +create database logical_database_db1 +go + +-- try to set GUC from TSQL endpoint. Should not effect information_schema_tsql.columns view +-- from TSQL endpoint it is a PG GUC +select set_config('psql_logical_babelfish_db_name', 'logical_database_db1', false) +go +~~START~~ +text +logical_database_db1 +~~END~~ + + +-- should return data of master as the current database is master +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases' +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#!#sysdatabases#!#name#!#1#!##!#YES#!#text#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!#C#!##!##!# +master#!#dbo#!#sysdatabases#!#dbid#!#2#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#sid#!#3#!##!#YES#!#varbinary#!#85#!#85#!##!##!##!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#mode#!#4#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#status#!#5#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#status2#!#6#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#crdate#!#7#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#reserved#!#8#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#category#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#cmptlevel#!#10#!##!#YES#!#tinyint#!##!##!#3#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +master#!#dbo#!#sysdatabases#!#filename#!#11#!##!#YES#!#nvarchar#!#260#!#520#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +master#!#dbo#!#sysdatabases#!#version#!#12#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +~~END~~ + + +use logical_database_db1 +go + +-- should return data of logical_database_db1 as the current database is logical_database_db1 +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases' +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 +logical_database_db1#!#dbo#!#sysdatabases#!#name#!#1#!##!#YES#!#text#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!#C#!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#dbid#!#2#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#sid#!#3#!##!#YES#!#varbinary#!#85#!#85#!##!##!##!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#mode#!#4#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#status#!#5#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#status2#!#6#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#crdate#!#7#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#reserved#!#8#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#category#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#cmptlevel#!#10#!##!#YES#!#tinyint#!##!##!#3#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#filename#!#11#!##!#YES#!#nvarchar#!#260#!#520#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#version#!#12#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +~~END~~ + + +create login logical_database_l1 with password = '12345678' +go + +alter server role sysadmin add member logical_database_l1 +go + +-- psql user=logical_database_l1 password=12345678 +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases'; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar"#!#varchar#!#"sys"."varchar"#!#int4#!#int4#!#int2#!#int2#!#int4#!#int2#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar" +~~END~~ + + +-- any user can set the GUC +set psql_logical_babelfish_db_name = 'logical_database_db1' +go + +select * from information_schema_tsql.columns where "TABLE_NAME"='sysdatabases'; +go +~~START~~ +"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#int4#!#"sys"."varchar"#!#varchar#!#"sys"."varchar"#!#int4#!#int4#!#int2#!#int2#!#int4#!#int2#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar"#!#"sys"."varchar" +logical_database_db1#!#dbo#!#sysdatabases#!#name#!#1#!##!#YES#!#text#!#2147483647#!#2147483647#!##!##!##!##!##!##!##!##!##!#C#!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#dbid#!#2#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#sid#!#3#!##!#YES#!#varbinary#!#85#!#85#!##!##!##!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#mode#!#4#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#status#!#5#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#status2#!#6#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#crdate#!#7#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#reserved#!#8#!##!#YES#!#datetime#!##!##!##!##!##!#3#!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#category#!#9#!##!#YES#!#int#!##!##!#10#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#cmptlevel#!#10#!##!#YES#!#tinyint#!##!##!#3#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#filename#!#11#!##!#YES#!#nvarchar#!#260#!#520#!##!##!##!##!##!##!##!##!##!#bbf_unicode_cp1_ci_as#!##!##!# +logical_database_db1#!#dbo#!#sysdatabases#!#version#!#12#!##!#YES#!#smallint#!##!##!#5#!#10#!#0#!##!##!##!##!##!##!##!##!##!# +~~END~~ + + +-- psql +-- Cleanup +-- 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) = 'logical_database_l1' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- tsql +use master +go + +drop login logical_database_l1 +go + +drop database logical_database_db1 +go diff --git a/test/JDBC/expected/rowcount-vu-cleanup.out b/test/JDBC/expected/rowcount-vu-cleanup.out new file mode 100644 index 0000000000..9236186ec4 --- /dev/null +++ b/test/JDBC/expected/rowcount-vu-cleanup.out @@ -0,0 +1,41 @@ +drop procedure rowcount_vu_prepare_insert_proc; +GO + +drop procedure rowcount_vu_prepare_select_proc; +GO + +drop procedure rowcount_vu_prepare_update_proc; +GO + +drop procedure rowcount_vu_prepare_delete_proc; +GO + + + +drop procedure rowcount_vu_prepare_insert_proc_var; +GO + +drop procedure rowcount_vu_prepare_select_proc_var; +GO + +drop procedure rowcount_vu_prepare_update_proc_var; +GO + +drop procedure rowcount_vu_prepare_delete_proc_var; +GO + +drop procedure rowcount_vu_prepare_select_nested_proc_var +go + +drop procedure rowcount_vu_prepare_select +go + +drop table rowcount_vu_prepare_testing1 +GO + +drop table rowcount_vu_prepare_testing2 +GO + + +drop table rowcount_vu_prepare_testing3 +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..7802ec25e9 --- /dev/null +++ b/test/JDBC/expected/rowcount-vu-prepare.out @@ -0,0 +1,132 @@ +create table rowcount_vu_prepare_testing1 (a int); +GO + +create table rowcount_vu_prepare_testing2 (a int); +go + +create table rowcount_vu_prepare_testing3(k int, value int) +go + +insert into rowcount_vu_prepare_testing3 values(1,1), (1,2), (1,3); +go +~~ROW COUNT: 3~~ + + +-- procedures to test "SET ROWCOUNT value" +create procedure rowcount_vu_prepare_insert_proc as +begin + set rowcount 1; + insert into rowcount_vu_prepare_testing1 values (1); + insert into rowcount_vu_prepare_testing1 values (1); + insert into rowcount_vu_prepare_testing1 select a + 1 from rowcount_vu_prepare_testing1; + insert into rowcount_vu_prepare_testing1 select a + 1 from rowcount_vu_prepare_testing1; + set rowcount 0; + set rowcount 5; + insert into rowcount_vu_prepare_testing1 select a from rowcount_vu_prepare_testing1; + insert into rowcount_vu_prepare_testing1 select a from rowcount_vu_prepare_testing1; + set rowcount 0; +end +GO + +create procedure rowcount_vu_prepare_select_proc as +begin + set rowcount 1; + select count(*) from rowcount_vu_prepare_testing1; + select * from rowcount_vu_prepare_testing1; + set rowcount 0; +end +GO + +create procedure rowcount_vu_prepare_update_proc as +begin + set rowcount 1; + select count(*) from rowcount_vu_prepare_testing1; + update rowcount_vu_prepare_testing1 set a = 10; + select count(*) from rowcount_vu_prepare_testing1 where a = 10; + set rowcount 0; +end +GO + +create procedure rowcount_vu_prepare_delete_proc as +begin + set rowcount 1; + select count(*) from rowcount_vu_prepare_testing1 where a = 1; + delete from rowcount_vu_prepare_testing1 where a = 1; + select count(*) from rowcount_vu_prepare_testing1 where a = 1; + set rowcount 0; +end +GO + +-- procedures to test "SET ROWCOUNT @variable" +create procedure rowcount_vu_prepare_insert_proc_var as +begin + declare @v int = 1; + set rowcount @v; + insert into rowcount_vu_prepare_testing2 values (1); + insert into rowcount_vu_prepare_testing2 values (1); + insert into rowcount_vu_prepare_testing2 select a + 1 from rowcount_vu_prepare_testing2; + insert into rowcount_vu_prepare_testing2 select a + 1 from rowcount_vu_prepare_testing2; + declare @x int = 0; + set rowcount @x; + set @x = 5; + set rowcount @x; + insert into rowcount_vu_prepare_testing2 select a from rowcount_vu_prepare_testing2; + insert into rowcount_vu_prepare_testing2 select a from rowcount_vu_prepare_testing2; + set rowcount 0; +end +GO + +create procedure rowcount_vu_prepare_select_proc_var as +begin + declare @v smallint = 1; + set rowcount @v; + select count(*) from rowcount_vu_prepare_testing2; + select * from rowcount_vu_prepare_testing2; + declare @x int = 0; + set rowcount @x; +end +GO + +create procedure rowcount_vu_prepare_update_proc_var as +begin + declare @v smallint = 1; + set rowcount @v; + select count(*) from rowcount_vu_prepare_testing2; + update rowcount_vu_prepare_testing2 set a = 10; + select count(*) from rowcount_vu_prepare_testing2 where a = 10; + declare @x int = 0; + set rowcount @x; +end +GO + +create procedure rowcount_vu_prepare_delete_proc_var as +begin + declare @v smallint = 1; + set rowcount @v; + select count(*) from rowcount_vu_prepare_testing2 where a = 1; + delete from rowcount_vu_prepare_testing2 where a = 1; + select count(*) from rowcount_vu_prepare_testing2 where a = 1; + set rowcount 0; +end +GO + +create procedure rowcount_vu_prepare_select as +begin + select * from rowcount_vu_prepare_testing2; +end +go + + + +create procedure rowcount_vu_prepare_select_nested_proc_var as +begin + declare @v smallint = 1; + set rowcount @v; + select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; + exec rowcount_vu_prepare_select; + declare @x int = 0; + set rowcount @x; + select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; + exec rowcount_vu_prepare_select; +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..2f3559f7b9 --- /dev/null +++ b/test/JDBC/expected/rowcount-vu-verify.out @@ -0,0 +1,370 @@ + +-- test "SET ROWCOUNT value" +exec rowcount_vu_prepare_insert_proc; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 5~~ + + +exec rowcount_vu_prepare_select_proc; +GO +~~START~~ +int +13 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +exec rowcount_vu_prepare_update_proc; +GO +~~START~~ +int +13 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +exec rowcount_vu_prepare_delete_proc; +GO +~~START~~ +int +6 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +5 +~~END~~ + + + +-- test "SET ROWCOUNT @variable" +exec rowcount_vu_prepare_insert_proc_var; +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 5~~ + + +exec rowcount_vu_prepare_select_proc_var; +GO +~~START~~ +int +13 +~~END~~ + +~~START~~ +int +1 +~~END~~ + + +exec rowcount_vu_prepare_update_proc_var; +GO +~~START~~ +int +13 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + + +exec rowcount_vu_prepare_delete_proc_var; +GO +~~START~~ +int +6 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +5 +~~END~~ + + + +-- check value +select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; +go +~~START~~ +text +2147483647 +~~END~~ + + +-- nested proc +exec rowcount_vu_prepare_select_nested_proc_var +go +~~START~~ +text +1 +~~END~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +text +0 +~~END~~ + +~~START~~ +int +2 +2 +1 +1 +2 +2 +1 +1 +2 +2 +1 +10 +~~END~~ + + +-- should throw syntax error +set rowcount -1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near '-' at line 2 and character position 13)~~ + + +set rowcount NULL +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: syntax error near 'NULL' at line 1 and character position 13)~~ + + +-- should throw error +declare @v smallint = -1 +set rowcount @v +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: -1 is outside the valid range for parameter "babelfishpg_tsql.rowcount" (0 .. 2147483647))~~ + + +declare @v smallint = NULL +SET ROWCOUNT @v +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid argument for SET ROWCOUNT. Must be a non-null value.)~~ + + +-- invalid set should throw error +DECLARE @value date = '2006-01-02' +SET ROWCOUNT @value +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "2006-01-02")~~ + + +-- invalid set should throw error +DECLARE @value varchar(10) = 'abc' +SET ROWCOUNT @value +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type integer: "abc")~~ + + +-- check value +select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; +go +~~START~~ +text +2147483647 +~~END~~ + + +-- implicit cast is allowed +DECLARE @value varchar(10) = '123' +SET ROWCOUNT @value +GO + +select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; +go +~~START~~ +text +123 +~~END~~ + + +-- set int/bigint/smallint +DECLARE @value int = 2147483647 +SET ROWCOUNT @value +GO + +select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; +go +~~START~~ +text +2147483647 +~~END~~ + + +-- overflow should throw error +DECLARE @value bigint = 922337203685477580 +SET ROWCOUNT @value +GO +~~ERROR (Code: 8115)~~ + +~~ERROR (Message: integer out of range)~~ + + +SET ROWCOUNT 2147483649 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid value for parameter "babelfishpg_tsql.rowcount": "2147483649")~~ + + +select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; +go +~~START~~ +text +2147483647 +~~END~~ + + +DECLARE @value smallint = 3276 +SET ROWCOUNT @value +GO + +select setting from pg_settings where name = 'babelfishpg_tsql.rowcount'; +go +~~START~~ +text +3276 +~~END~~ + + +-- while loop +DECLARE @value smallint = 1 +set rowcount @value +go + +while 1=1 +begin + SELECT * from rowcount_vu_prepare_testing3 where k = 1; + UPDATE rowcount_vu_prepare_testing3 SET k = 2 where k = 1; + SELECT * from rowcount_vu_prepare_testing3 where k = 2; + DELETE rowcount_vu_prepare_testing3 where k = 2; + if @@rowcount = 0 break +end +go +~~START~~ +int#!#int +1#!#1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +2#!#1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +2#!#2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#3 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +2#!#3 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +~~END~~ + +~~START~~ +int#!#int +~~END~~ + + + +-- error message should be in uppercase for stmt +declare @v int = NULL; +SET rowCounT @v +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Invalid argument for SET ROWCOUNT. Must be a non-null value.)~~ + + + +-- parameter name should be in lowercase for stmt +declare @v int = -1; +SET rowCounT @v +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: -1 is outside the valid range for parameter "babelfishpg_tsql.rowcount" (0 .. 2147483647))~~ + diff --git a/test/JDBC/expected/select-strip-parens-before-15_5-vu-cleanup.out b/test/JDBC/expected/select-strip-parens-before-15_5-vu-cleanup.out new file mode 100644 index 0000000000..cb4df1279d --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-before-15_5-vu-cleanup.out @@ -0,0 +1,4 @@ +drop view select_strip_parens_v1; +go +drop table select_strip_parens_t1; +go diff --git a/test/JDBC/expected/select-strip-parens-before-15_5-vu-prepare.out b/test/JDBC/expected/select-strip-parens-before-15_5-vu-prepare.out new file mode 100644 index 0000000000..25d504c731 --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-before-15_5-vu-prepare.out @@ -0,0 +1,12 @@ +create table select_strip_parens_t1(field1 int, " field2 " int, [ field3 ] int); +go + +insert into select_strip_parens_t1(field1, " field2 ", [ field3 ]) values(41, 42, 43); +go +~~ROW COUNT: 1~~ + + +create view select_strip_parens_v1 as +select ( ( field1 ) ), ( ( " field2 " ) ), ( ( [ field3 ] ) ) +from select_strip_parens_t1; +go diff --git a/test/JDBC/expected/select-strip-parens-before-15_5-vu-verify.out b/test/JDBC/expected/select-strip-parens-before-15_5-vu-verify.out new file mode 100644 index 0000000000..a1b4098a4e --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-before-15_5-vu-verify.out @@ -0,0 +1,278 @@ +-- unquoted field successfull queries +select field1 from (select field1 from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select (field1) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ((field1)) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( ( field1 ) ) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( field1 ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( "field1" ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( [field1] ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select field1 from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select (field1) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ((field1)) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( ( field1 ) ) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( field1 ) +) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( "field1" ) +) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( [field1] ) +) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + + +-- unquoted field failed queries +select field1 from (select " field1" from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select " field1" from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select [ field1] from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select [ field1] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( " field1" ) +) from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( " field1" ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( [ field1] ) +) from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( [ field1] ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + + +-- quoted fields successfull queries +select " field2 ", [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select [ field2 ], [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select (" field2 "), ([ field3 ]) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ((" field2 ")), (([ field3 ])) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( ( " field2 " ) ), ( ( [ field3 ] ) ) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + + +select " field2 ", [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", " field3 " from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select (" field2 "), ([ field3 ]) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ((" field2 ")), (([ field3 ])) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( ( " field2 " ) ), ( ( [ field3 ] ) ) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + + +-- quoted fields failed queries +select " field2 " from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field3 " does not exist)~~ + diff --git a/test/JDBC/expected/select-strip-parens-before-pr1812-vu-cleanup.out b/test/JDBC/expected/select-strip-parens-before-pr1812-vu-cleanup.out new file mode 100644 index 0000000000..cb4df1279d --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-before-pr1812-vu-cleanup.out @@ -0,0 +1,4 @@ +drop view select_strip_parens_v1; +go +drop table select_strip_parens_t1; +go diff --git a/test/JDBC/expected/select-strip-parens-before-pr1812-vu-prepare.out b/test/JDBC/expected/select-strip-parens-before-pr1812-vu-prepare.out new file mode 100644 index 0000000000..8633191140 --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-before-pr1812-vu-prepare.out @@ -0,0 +1,18 @@ +create table select_strip_parens_t1(field1 int, " field2 " int, [ field3 ] int); +go + +insert into select_strip_parens_t1(field1, " field2 ", [ field3 ]) values(41, 42, 43); +go +~~ROW COUNT: 1~~ + + +create view select_strip_parens_v1 as +select ( + ( field1 ) +), ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) +from select_strip_parens_t1; +go diff --git a/test/JDBC/expected/select-strip-parens-before-pr1812-vu-verify.out b/test/JDBC/expected/select-strip-parens-before-pr1812-vu-verify.out new file mode 100644 index 0000000000..1fa07fb6b2 --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-before-pr1812-vu-verify.out @@ -0,0 +1,264 @@ +-- unquoted field successfull queries +select field1 from (select field1 from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select (field1) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ((field1)) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( ( field1 ) ) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( field1 ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( "field1" ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( [field1] ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + + +-- unquoted field failed queries +select field1 from (select field1 from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select (field1) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select ((field1)) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select ( ( field1 ) ) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select ( + ( field1 ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select ( + ( "field1" ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select ( + ( [field1] ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "field1" does not exist)~~ + +select field1 from (select " field1" from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select " field1" from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select [ field1] from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select [ field1] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( " field1" ) +) from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( " field1" ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( [ field1] ) +) from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( [ field1] ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + + +-- quoted fields successfull queries +select " field2 ", [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select [ field2 ], [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select (" field2 "), ([ field3 ]) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ((" field2 ")), (([ field3 ])) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( ( " field2 " ) ), ( ( [ field3 ] ) ) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + + +-- quoted fields failed queries +select " field2 ", [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select " field2 ", " field3 " from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select " field2 ", [ field3 ] from (select (" field2 "), ([ field3 ]) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select " field2 ", [ field3 ] from (select ((" field2 ")), (([ field3 ])) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select " field2 ", [ field3 ] from (select ( ( " field2 " ) ), ( ( [ field3 ] ) ) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select " field2 ", [ field3 ] from (select ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select " field2 " from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + diff --git a/test/JDBC/expected/select-strip-parens-vu-cleanup.out b/test/JDBC/expected/select-strip-parens-vu-cleanup.out new file mode 100644 index 0000000000..cb4df1279d --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-vu-cleanup.out @@ -0,0 +1,4 @@ +drop view select_strip_parens_v1; +go +drop table select_strip_parens_t1; +go diff --git a/test/JDBC/expected/select-strip-parens-vu-prepare.out b/test/JDBC/expected/select-strip-parens-vu-prepare.out new file mode 100644 index 0000000000..8633191140 --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-vu-prepare.out @@ -0,0 +1,18 @@ +create table select_strip_parens_t1(field1 int, " field2 " int, [ field3 ] int); +go + +insert into select_strip_parens_t1(field1, " field2 ", [ field3 ]) values(41, 42, 43); +go +~~ROW COUNT: 1~~ + + +create view select_strip_parens_v1 as +select ( + ( field1 ) +), ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) +from select_strip_parens_t1; +go diff --git a/test/JDBC/expected/select-strip-parens-vu-verify.out b/test/JDBC/expected/select-strip-parens-vu-verify.out new file mode 100644 index 0000000000..08f830496f --- /dev/null +++ b/test/JDBC/expected/select-strip-parens-vu-verify.out @@ -0,0 +1,277 @@ +-- unquoted field successfull queries +select field1 from (select field1 from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select field1 from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select (field1) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select (field1) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ((field1)) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ((field1)) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( ( field1 ) ) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( ( field1 ) ) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( field1 ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( field1 ) +) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( "field1" ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( "field1" ) +) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( [field1] ) +) from select_strip_parens_t1) a; +go +~~START~~ +int +41 +~~END~~ + +select field1 from (select ( + ( [field1] ) +) from select_strip_parens_v1) a; +go +~~START~~ +int +41 +~~END~~ + + +-- unquoted field failed queries +select field1 from (select " field1" from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select " field1" from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select [ field1] from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select [ field1] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( " field1" ) +) from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( " field1" ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( [ field1] ) +) from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + +select field1 from (select ( + ( [ field1] ) +) from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field1" does not exist)~~ + + +-- quoted fields successfull queries +select " field2 ", [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select [ field2 ], [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", " field3 " from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select (" field2 "), ([ field3 ]) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select (" field2 "), ([ field3 ]) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ((" field2 ")), (([ field3 ])) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ((" field2 ")), (([ field3 ])) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( ( " field2 " ) ), ( ( [ field3 ] ) ) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( ( " field2 " ) ), ( ( [ field3 ] ) ) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) from select_strip_parens_t1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + +select " field2 ", [ field3 ] from (select ( + ( " field2 " ) +), ( + ( [ field3 ] ) +) from select_strip_parens_v1) a; +go +~~START~~ +int#!#int +42#!#43 +~~END~~ + + +-- quoted fields failed queries +select " field2 " from (select " field2 ", [ field3 ] from select_strip_parens_t1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field2 " does not exist)~~ + +select [ field3 ] from (select " field2 ", [ field3 ] from select_strip_parens_v1) a; +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column " field3 " does not exist)~~ + diff --git a/test/JDBC/expected/smalldatetimefromparts-dep-vu-cleanup.out b/test/JDBC/expected/smalldatetimefromparts-dep-vu-cleanup.out new file mode 100644 index 0000000000..14310a5716 --- /dev/null +++ b/test/JDBC/expected/smalldatetimefromparts-dep-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP VIEW smalldatetimefromparts_vu_prepare_v1 +GO + +DROP VIEW smalldatetimefromparts_vu_prepare_v2 +GO + +DROP PROCEDURE smalldatetimefromparts_vu_prepare_p1 +GO + +DROP PROCEDURE smalldatetimefromparts_vu_prepare_p2 +GO + +DROP FUNCTION smalldatetimefromparts_vu_prepare_f1() +GO + +DROP FUNCTION smalldatetimefromparts_vu_prepare_f2() +GO diff --git a/test/JDBC/expected/smalldatetimefromparts-dep-vu-prepare.out b/test/JDBC/expected/smalldatetimefromparts-dep-vu-prepare.out new file mode 100644 index 0000000000..26359c3f04 --- /dev/null +++ b/test/JDBC/expected/smalldatetimefromparts-dep-vu-prepare.out @@ -0,0 +1,25 @@ +CREATE VIEW smalldatetimefromparts_vu_prepare_v1 as (SELECT SMALLDATETIMEFROMPARTS(2011, 8, 15, 14, 30)); +GO + +CREATE VIEW smalldatetimefromparts_vu_prepare_v2 as (SELECT SMALLDATETIMEFROMPARTS(2011, 8, 15, NULL, 30)); +GO + +CREATE PROCEDURE smalldatetimefromparts_vu_prepare_p1 as (SELECT SMALLDATETIMEFROMPARTS(2011, 8, 15, 14, 30)); +GO + +CREATE PROCEDURE smalldatetimefromparts_vu_prepare_p2 as (SELECT SMALLDATETIMEFROMPARTS(2076, 8, 15, 22, 30)); +GO + +CREATE FUNCTION smalldatetimefromparts_vu_prepare_f1() +RETURNS SMALLDATETIME AS +BEGIN +RETURN (SELECT SMALLDATETIMEFROMPARTS(2079, 8, 15, 14, 30)); +END +GO + +CREATE FUNCTION smalldatetimefromparts_vu_prepare_f2() +RETURNS SMALLDATETIME as +begin +RETURN (SELECT SMALLDATETIMEFROMPARTS(1899, 8, 15, NULL, 30)); +END +GO diff --git a/test/JDBC/expected/smalldatetimefromparts-dep-vu-verify.out b/test/JDBC/expected/smalldatetimefromparts-dep-vu-verify.out new file mode 100644 index 0000000000..7d4095db02 --- /dev/null +++ b/test/JDBC/expected/smalldatetimefromparts-dep-vu-verify.out @@ -0,0 +1,48 @@ +SELECT * FROM smalldatetimefromparts_vu_prepare_v1 +GO +~~START~~ +smalldatetime +2011-08-15 14:30:00.0 +~~END~~ + + +SELECT * FROM smalldatetimefromparts_vu_prepare_v2 +GO +~~START~~ +smalldatetime + +~~END~~ + + +EXEC smalldatetimefromparts_vu_prepare_p1 +GO +~~START~~ +smalldatetime +2011-08-15 14:30:00.0 +~~END~~ + + +EXEC smalldatetimefromparts_vu_prepare_p2 +GO +~~START~~ +smalldatetime +2076-08-15 22:30:00.0 +~~END~~ + + +SELECT smalldatetimefromparts_vu_prepare_f1() +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT smalldatetimefromparts_vu_prepare_f2() +GO +~~START~~ +smalldatetime + +~~END~~ + diff --git a/test/JDBC/expected/smalldatetimefromparts.out b/test/JDBC/expected/smalldatetimefromparts.out new file mode 100644 index 0000000000..5971a61cc2 --- /dev/null +++ b/test/JDBC/expected/smalldatetimefromparts.out @@ -0,0 +1,565 @@ +SELECT SMALLDATETIMEFROMPARTS ( 1899, 12, 31, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1899, 01, 01, 00, 00 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1900, 12, 31, 23, 59 ) AS Result +go +~~START~~ +smalldatetime +1900-12-31 23:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1900, 1, 1, 00, 00 ) AS Result +go +~~START~~ +smalldatetime +1900-01-01 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, 00, NULL ) AS Result +GO +~~START~~ +smalldatetime + +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, NULL, 23 ) AS Result +GO +~~START~~ +smalldatetime + +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, NULL, 00, 23 ) AS Result +GO +~~START~~ +smalldatetime + +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, NULL, 01, 00, 23 ) AS Result +GO +~~START~~ +smalldatetime + +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( NULL, 1, 01, 00, 13 ) AS Result +GO +~~START~~ +smalldatetime + +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( NULL,NULL, NULL, NULL, NULL ) AS Result +GO +~~START~~ +smalldatetime + +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1899, 6, 30, 23, 59 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1900, 13, 31, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 12, 31, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2080, 1 , 1 , 00 , 0 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 12, 31, 23, 59 ) AS Result +go +~~START~~ +smalldatetime +2078-12-31 23:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 13, 31, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 1, 1, 00, 00 ) AS Result +GO +~~START~~ +smalldatetime +2079-01-01 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 1, 1, 00, ' 00' ) AS Result +GO +~~START~~ +smalldatetime +2079-01-01 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 00, 31, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 0, 31, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 6, 6, 23, 59) AS Result +GO +~~START~~ +smalldatetime +2079-06-06 23:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 6, 7, 00, 00) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 7, 6, 00, 00) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 01, 31, 23, 59 ) AS Result +go +~~START~~ +smalldatetime +2078-01-31 23:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 31, 23, 59 ) AS Result +go +~~START~~ +smalldatetime +2078-01-31 23:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 32, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 0, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 00, 23, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, 23, 59 ) AS Result +go +~~START~~ +smalldatetime +2078-01-01 23:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, 24, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, 00, 59 ) AS Result +go +~~START~~ +smalldatetime +2078-01-01 00:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -01, 59 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -00, 59 ) AS Result +go +~~START~~ +smalldatetime +2078-01-01 00:59:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -00, 60 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -00, 00 ) AS Result +go +~~START~~ +smalldatetime +2078-01-01 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -00, 0 ) AS Result +go +~~START~~ +smalldatetime +2078-01-01 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -00, -1 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 01, -00, -01 ) AS Result +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( '2078', 1, 01, 00, 22) AS Result +GO +~~START~~ +smalldatetime +2078-01-01 00:22:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ('2078','1','01','00','22' ) AS Result +GO +~~START~~ +smalldatetime +2078-01-01 00:22:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078.03, 1, 01, 00, 22 ) AS Result +GO +~~START~~ +smalldatetime +2078-01-01 00:22:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078.45, 1, 01, 00, 22 ) AS Result +GO +~~START~~ +smalldatetime +2078-01-01 00:22:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078.60, 1, 01, 00, 22 ) AS Result +GO +~~START~~ +smalldatetime +2078-01-01 00:22:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078.60, 1.0, 0.1, 0.0, 2.2 ) AS Result +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1.0, 2, 0, 2 ) AS Result +GO +~~START~~ +smalldatetime +2078-01-02 00:02:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 2, 0.0, 2 ) AS Result +GO +~~START~~ +smalldatetime +2078-01-02 00:02:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2078, 1, 2, 0, 2.0 ) AS Result +GO +~~START~~ +smalldatetime +2078-01-02 00:02:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( cast(2078 as varchar), cast(1 as numeric), cast(2 as bigint), cast(0 as float), cast(2 as real) ) AS Result +GO +~~START~~ +smalldatetime +2078-01-02 00:02:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( cast(0x12 as int), 1, 2, 0, 2.0 ) AS Result +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( cast(0x123 as int), 1, 2, 0, 2.0 ) AS Result +GO +~~START~~ +smalldatetime +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1017*2,2*5, 4*5, 2*11, 14*2*2 ) AS Result +GO +~~START~~ +smalldatetime +2034-10-20 22:56:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( cast(0x7D0 as int), 1, 2, 0, 2.0 ) AS Result +GO +~~START~~ +smalldatetime +2000-01-02 00:02:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 1, 1, 00, 2.2 ) AS Result +GO +~~START~~ +smalldatetime +2079-01-01 00:02:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 1, 2,-3,4) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, 1, -2,3,4) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 2079, -1,2,3,4) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS (- 2079, 1,2,3,4) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS (2079, 1,2,3,4) AS Result +GO +~~START~~ +smalldatetime +2079-01-02 03:04:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 1, 7, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-01-07 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 3, 7, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-03-07 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 1899, 1, 1, 0, 0 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 7, 6, 0, 0 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1900, 0, 1, 00, 00 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS ( 1900, 1, 0, 00, 00 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 6, 6, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-06-06 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 5, 6, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-05-06 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 6, 5, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-06-05 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 6, 4, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-06-04 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 6, 3, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-06-03 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 7, 1, 0, 0 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 6, 7, 0, 0 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 6, 5, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-06-05 00:00:00.0 +~~END~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 7, 6, 0, 0 ) AS Result +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type smalldatetime, some of the arguments have values which are not valid.)~~ + + +SELECT SMALLDATETIMEFROMPARTS( 2079, 5, 7, 0, 0 ) AS Result +GO +~~START~~ +smalldatetime +2079-05-07 00:00:00.0 +~~END~~ + + diff --git a/test/JDBC/expected/sp_changedbowner-vu-cleanup.out b/test/JDBC/expected/sp_changedbowner-vu-cleanup.out new file mode 100644 index 0000000000..b9b75a390f --- /dev/null +++ b/test/JDBC/expected/sp_changedbowner-vu-cleanup.out @@ -0,0 +1,26 @@ +-- tsql +-- cleanup +use master +go +drop login dba_login_sp +go +drop login new_OWNER_login_sp +go +drop login new_OWNER_login_sp2 +go +drop login [new_OWNER_login_sp3] +go +drop login [new_OWNER_login_sp 4] +go +set quoted_identifier on +go +drop login "new_OWNER_login_sp5" +go +drop login "new_OWNER_login_sp 6" +go +set quoted_identifier off +go +drop login LOGIN64long_3456789012345678901234567890123456789012345678901234 +go +drop login LOGIN63long_345678901234567890123456789012345678901234567890123 +go diff --git a/test/JDBC/expected/sp_changedbowner-vu-prepare.out b/test/JDBC/expected/sp_changedbowner-vu-prepare.out new file mode 100644 index 0000000000..941e654a7d --- /dev/null +++ b/test/JDBC/expected/sp_changedbowner-vu-prepare.out @@ -0,0 +1,21 @@ +-- tsql +use master +go +create login dba_login_sp with password='12345678' +go +create login new_OWNER_login_sp with password='12345678' +go +create login new_OWNER_login_sp2 with password='12345678' +go +create login [new_OWNER_login_sp3] with password='12345678' +go +create login [new_OWNER_login_sp 4] with password='12345678' +go +set quoted_identifier on +go +create login "new_OWNER_login_sp5" with password='12345678' +go +create login "new_OWNER_login_sp 6" with password='12345678' +go +set quoted_identifier off +go diff --git a/test/JDBC/expected/sp_changedbowner-vu-verify.out b/test/JDBC/expected/sp_changedbowner-vu-verify.out new file mode 100644 index 0000000000..a9555bee05 --- /dev/null +++ b/test/JDBC/expected/sp_changedbowner-vu-verify.out @@ -0,0 +1,424 @@ + +-- tsql +-- sp_changedbowner: this is a subset of the tests for C:\Babelfish\code\work\chgdbowner\alter_authorization_change_db_owner +use master +go +alter login dba_login_sp with password='12345678' +go +alter server role sysadmin add member dba_login_sp +go +alter login new_OWNER_login_sp with password='12345678' +go +alter login new_OWNER_login_sp2 with password='12345678' +go +alter login [new_OWNER_login_sp3] with password='12345678' +go +alter login [new_OWNER_login_sp 4] with password='12345678' +go +set quoted_identifier on +go +alter login "new_OWNER_login_sp5" with password='12345678' +go +alter login "new_OWNER_login_sp 6" with password='12345678' +go +set quoted_identifier off +go + +-- tsql user=dba_login_sp password=12345678 +-- system database ownership cannot be changed +use master +go +execute sp_changedbowner 'new_owner_login_sp' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot change the owner of the master or tempdb database.)~~ + +use tempdb +go +execute sp_changedbowner 'new_owner_login_sp' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot change the owner of the master or tempdb database.)~~ + + +-- except for msdb +use msdb +go +execute sp_changedbowner new_owner_login_sp +go +select name, suser_sname(sid) from sysdatabases where name = 'msdb' +go +~~START~~ +text#!#nvarchar +msdb#!#new_OWNER_login_sp +~~END~~ + +execute sp_changedbowner dba_login_sp +go +select name, suser_sname(sid) from sysdatabases where name = 'msdb' +go +~~START~~ +text#!#nvarchar +msdb#!#dba_login_sp +~~END~~ + +use master +go + +-- tsql +use msdb +go +declare @v varchar(30) = suser_name() +execute sp_changedbowner @v +go +use master +go + +-- tsql user=dba_login_sp password=12345678 +use master +go +create database change_OWNER_db_sp +go +use change_owner_DB_SP +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#dba_login_sp +~~END~~ + +execute sp_changedbowner 'no_such_login_sp' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal 'no_such_login_sp', because it does not exist or you do not have permission.)~~ + + +-- new owner cannot be a user in the DB already +create user new_owner_login_sp +go +execute sp_changedbowner new_owner_login_sp +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The proposed new database owner is already a user or aliased in the database.)~~ + +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#dba_login_sp +~~END~~ + +drop user new_owner_login_sp +go +execute sp_changedbowner new_owner_LOGIN_SP +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + + +-- tsql user=new_owner_LOGIN_SP password=12345678 +use CHANGE_OWNER_DB_SP +go +select user_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dbo#!#change_owner_db_sp +~~END~~ + +use master +go + +-- tsql user=dba_login_sp password=12345678 +-- second argument is ignored +use change_owner_db_sp +go +execute sp_changedbowner NEW_owner_login_sp2, null +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp2 +~~END~~ + +execute sp_changedbowner [new_owner_LOGIN_SP3], 12345 +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp3 +~~END~~ + +execute sp_changedbowner [NEW_owner_login_sp3], 'abcde' +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp3 +~~END~~ + +execute sp_changedbowner [new_owner_LOGIN_SP 4], 'abcdefgh' +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp 4 +~~END~~ + +execute sp_changedbowner "NEW_owner_login_sp5" +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp5 +~~END~~ + +execute sp_changedbowner @loginame = "new_owner_LOGIN_SP 6", @map = 'some-string' +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp 6 +~~END~~ + + +use change_owner_db_sp +go +execute sp_changedbowner "new_owner_login_sp" +go +use master +go + +-- tsql user=new_owner_LOGIN_SP password=12345678 +-- change owner to yourself +use change_owner_db_sp +go +select user_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dbo#!#change_owner_db_sp +~~END~~ + +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + +execute sp_changedbowner "new_owner_login_sp" +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + +execute sp_changedbowner "NEW_OWNER_LOGIN_SP" +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + +execute sp_changedbowner [NEW_owner_login_sp] +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + +use master +go + +-- tsql user=dba_login_sp password=12345678 +-- roll back owner change in transaction +use change_owner_db_sp +go +begin tran +go +select 'before owner change', name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +varchar#!#text#!#nvarchar +before owner change#!#change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + +execute sp_changedbowner NEW_owner_login_sp2 +go +select 'after owner change', name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +varchar#!#text#!#nvarchar +after owner change#!#change_owner_db_sp#!#new_OWNER_login_sp2 +~~END~~ + +rollback +go +select 'after rollback', name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +varchar#!#text#!#nvarchar +after rollback#!#change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + + + +-- NULL as new owner is a no-op +execute sp_changedbowner NULL +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + +execute sp_changedbowner @loginame=NULL +go +select name, suser_sname(sid) from sysdatabases where lower(name) = 'change_owner_db_sp' +go +~~START~~ +text#!#nvarchar +change_owner_db_sp#!#new_OWNER_login_sp +~~END~~ + + +-- non-existing logins +execute sp_changedbowner '' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal '', because it does not exist or you do not have permission.)~~ + +execute sp_changedbowner ' ' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal ' ', because it does not exist or you do not have permission.)~~ + +execute sp_changedbowner @loginame=' ' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal ' ', because it does not exist or you do not have permission.)~~ + +execute sp_changedbowner [ ] +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal ' ', because it does not exist or you do not have permission.)~~ + +execute sp_changedbowner @loginame=[ ] +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal ' ', because it does not exist or you do not have permission.)~~ + +use master +go +drop database change_owner_db_sp +go + +-- tests for long names and mixed case +create login LOGIN63long_345678901234567890123456789012345678901234567890123 with password = '12345678' +go +create database DB63long_012345678901234567890123456789012345678901234567890123 +go +use DB63long_012345678901234567890123456789012345678901234567890123 +go +execute sp_changedbowner LOGIN63long_345678901234567890123456789012345678901234567890123 +go +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB63LONG%' +go +~~START~~ +text#!#nvarchar +db63long_012345678901234567890123456789012345678901234567890123#!#LOGIN63long_345678901234567890123456789012345678901234567890123 +~~END~~ + +use master +go + +-- tsql user=LOGIN63long_345678901234567890123456789012345678901234567890123 password=12345678 +use DB63long_012345678901234567890123456789012345678901234567890123 +go +select user_name(), db_name() +go +~~START~~ +nvarchar#!#nvarchar +dbo#!#db63long_012345678901234567890123456789012345678901234567890123 +~~END~~ + +use master +go +drop database DB63long_012345678901234567890123456789012345678901234567890123 +go + +-- tsql user=dba_login_sp password=12345678 +create login LOGIN64long_3456789012345678901234567890123456789012345678901234 with password = '12345678' +go +create database DB64long_0123456789012345678901234567890123456789012345678901234 +go +use DB64long_0123456789012345678901234567890123456789012345678901234 +go +-- this returns 'principal not found' due to a bug in SUSER_ID() for names > 63 chars +execute sp_changedbowner "LOGIN64long_3456789012345678901234567890123456789012345678901234" +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Cannot find the principal 'LOGIN64long_3456789012345678901234567890123456789012345678901234', because it does not exist or you do not have permission.)~~ + +select name, suser_sname(sid) from sysdatabases where upper(name) like 'DB64LONG%' +go +~~START~~ +text#!#nvarchar +db64long_012345678901234567890109e0da63a1cdb0673c21e39afa6178e9#!#dba_login_sp +~~END~~ + +use master +go +drop database DB64long_0123456789012345678901234567890123456789012345678901234 +go + +-- tsql +use master +go +set nocount on +go +-- kill remaining sessions +create table #killed(killed int) +go +declare @spid int, @cmd varchar(30) +while (1=1) +begin +select @spid = spid from sys.sysprocesses where spid <> @@spid and spid not in (select killed from #killed) +and (lower(loginname) like 'new_owner_login%' or lower(loginname) like 'login6%' or lower(loginname) = 'dba_login_sp') +if @@rowcount = 0 break +insert #killed values(@spid) +set @cmd = 'kill ' + convert(varchar, @spid) +execute(@cmd) +end +go +exec pg_sleep 3 +go diff --git a/test/JDBC/expected/sp_describe_first_result_set-vu-cleanup.out b/test/JDBC/expected/sp_describe_first_result_set-vu-cleanup.out index 461a743b02..db5faa4ee8 100644 --- a/test/JDBC/expected/sp_describe_first_result_set-vu-cleanup.out +++ b/test/JDBC/expected/sp_describe_first_result_set-vu-cleanup.out @@ -1,3 +1,5 @@ DROP TABLE test_table1; +DROP TABLE sp_describe_first_result_set_vu_prepare_t1; DROP PROCEDURE sp_describe_first_result_set_vu_prepare_procedure; +DROP PROCEDURE sp_describe_first_result_set_vu_prepare_procedure2; GO diff --git a/test/JDBC/expected/sp_describe_first_result_set-vu-prepare.out b/test/JDBC/expected/sp_describe_first_result_set-vu-prepare.out index 5b532a3371..6c8538db47 100644 --- a/test/JDBC/expected/sp_describe_first_result_set-vu-prepare.out +++ b/test/JDBC/expected/sp_describe_first_result_set-vu-prepare.out @@ -7,6 +7,15 @@ AS -- test for query length <= 8000 EXEC sp_describe_first_result_set N'select * from test_table1'; -- test for query length > 8000 - EXEC sp_describe_first_result_set N'select * from test_table1'; + EXEC sp_describe_first_result_set N'select * from test_table1'; GO +-- test babel-3857 +CREATE PROCEDURE sp_describe_first_result_set_vu_prepare_procedure2 +AS + EXEC sp_describe_first_result_set N'PRINT 1'; +GO + +-- babel-4275 +create table sp_describe_first_result_set_vu_prepare_t1 (col_a text, col_b bool, col_c int, col_d bigint, col_e text) +GO diff --git a/test/JDBC/expected/sp_describe_first_result_set-vu-verify.out b/test/JDBC/expected/sp_describe_first_result_set-vu-verify.out index 9f0bd7717a..13b8800a91 100644 --- a/test/JDBC/expected/sp_describe_first_result_set-vu-verify.out +++ b/test/JDBC/expected/sp_describe_first_result_set-vu-verify.out @@ -18,3 +18,22 @@ bit#!#int#!#varchar#!#bit#!#int#!#nvarchar#!#smallint#!#tinyint#!#tinyint#!#varc ~~ERROR (Message: syntax error near '' at line 1 and character position 8000)~~ + +EXEC sp_describe_first_result_set_vu_prepare_procedure2; +GO +~~START~~ +bit#!#int#!#varchar#!#bit#!#int#!#nvarchar#!#smallint#!#tinyint#!#tinyint#!#varchar#!#int#!#varchar#!#varchar#!#varchar#!#nvarchar#!#int#!#varchar#!#varchar#!#varchar#!#bit#!#bit#!#bit#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#smallint#!#smallint#!#smallint#!#int#!#int#!#int#!#tinyint +~~END~~ + + +EXEC sp_describe_first_result_set N'select * from sp_describe_first_result_set_vu_prepare_t1' +GO +~~START~~ +bit#!#int#!#varchar#!#bit#!#int#!#nvarchar#!#smallint#!#tinyint#!#tinyint#!#varchar#!#int#!#varchar#!#varchar#!#varchar#!#nvarchar#!#int#!#varchar#!#varchar#!#varchar#!#bit#!#bit#!#bit#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#smallint#!#smallint#!#smallint#!#int#!#int#!#int#!#tinyint +0#!#1#!#col_a#!#1#!#25#!#text#!#-1#!#0#!#0#!#bbf_unicode_cp1_ci_as#!##!##!##!##!##!##!##!##!##!#0#!#0#!#0#!##!##!##!##!##!#0#!##!#1#!#0#!#0#!##!##!##!#35#!#16#!#13632521#!#52 +0#!#2#!#col_b#!#1#!#16#!#boolean#!##!##!##!##!##!##!##!##!##!##!##!##!##!#0#!#0#!#0#!##!##!##!##!##!#0#!##!#1#!#0#!#0#!##!##!##!#0#!##!##!# +0#!#3#!#col_c#!#1#!#23#!#int#!#4#!#10#!#0#!##!##!##!##!##!##!##!##!##!##!#0#!#0#!#0#!##!##!##!##!##!#0#!##!#1#!#0#!#0#!##!##!##!#38#!#4#!##!# +0#!#4#!#col_d#!#1#!#20#!#bigint#!#8#!#19#!#0#!##!##!##!##!##!##!##!##!##!##!#0#!#0#!#0#!##!##!##!##!##!#0#!##!#1#!#0#!#0#!##!##!##!#38#!#8#!##!# +0#!#5#!#col_e#!#1#!#25#!#text#!#-1#!#0#!#0#!#bbf_unicode_cp1_ci_as#!##!##!##!##!##!##!##!##!##!#0#!#0#!#0#!##!##!##!##!##!#0#!##!#1#!#0#!#0#!##!##!##!#35#!#16#!#13632521#!#52 +~~END~~ + diff --git a/test/JDBC/expected/sp_enum_oledb_providers.out b/test/JDBC/expected/sp_enum_oledb_providers.out new file mode 100644 index 0000000000..1409f9e9be --- /dev/null +++ b/test/JDBC/expected/sp_enum_oledb_providers.out @@ -0,0 +1,41 @@ +-- tsql +-- Executing sp_enum_oledb_providers without tds_fdw extension (should not return anything) +EXEC sp_enum_oledb_providers +GO + +-- Creating a simple login which has lesser privilege than sysadmin role +create login linked_server_login with password = 'password' +GO + +-- tsql user=linked_server_login password=password +-- Executing sp_enum_oledb_providers stored procedure without system admin privilege (should throw error) +EXEC sp_enum_oledb_providers +GO +~~ERROR (Code: 15003)~~ + +~~ERROR (Message: Only members of the sysadmin role can execute this stored procedure.)~~ + + +-- 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) = 'linked_server_login' AND backend_type = 'client backend' AND usesysid IS NOT NULL; +GO +~~START~~ +bool +t +~~END~~ + + +-- Wait to sync with another session +SELECT pg_sleep(1); +GO +~~START~~ +void + +~~END~~ + + +-- tsql +DROP LOGIN linked_server_login +GO diff --git a/test/JDBC/expected/sp_proc.out b/test/JDBC/expected/sp_proc.out index e7e2d0464c..c88ceb5dbb 100644 --- a/test/JDBC/expected/sp_proc.out +++ b/test/JDBC/expected/sp_proc.out @@ -17,6 +17,22 @@ int ~~END~~ +exec master.dbo.sp_hello +go +~~START~~ +int +1 +~~END~~ + + +exec master..sp_hello +go +~~START~~ +int +1 +~~END~~ + + create database db1 go @@ -31,7 +47,7 @@ int ~~END~~ -exec sp_hello +exec master..sp_hello go ~~START~~ int @@ -39,7 +55,7 @@ int ~~END~~ -sp_hello +exec sp_hello go ~~START~~ int @@ -71,6 +87,46 @@ int ~~END~~ +exec .dbo.sp_hello +go +~~START~~ +int +1 +~~END~~ + + +exec ..dbo.sp_hello +go +~~START~~ +int +1 +~~END~~ + + +sp_hello +go +~~START~~ +int +1 +~~END~~ + + +.sp_hello +go +~~START~~ +int +1 +~~END~~ + + +..sp_hello +go +~~START~~ +int +1 +~~END~~ + + dbo.sp_hello go ~~START~~ @@ -79,6 +135,22 @@ int ~~END~~ +.dbo.sp_hello +go +~~START~~ +int +1 +~~END~~ + + +..dbo.sp_hello +go +~~START~~ +int +1 +~~END~~ + + create proc call_sp_helllo as exec sp_hello go 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/expected/sp_who-vu-cleanup.out b/test/JDBC/expected/sp_who-vu-cleanup.out new file mode 100644 index 0000000000..f412ef927d --- /dev/null +++ b/test/JDBC/expected/sp_who-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP TABLE t_sp_who +go + +DROP TABLE [sp_who test table] +go + +DROP LOGIN sp_who_login +GO + +DROP PROCEDURE sp_who_myprocedure +go diff --git a/test/JDBC/expected/sp_who-vu-prepare.out b/test/JDBC/expected/sp_who-vu-prepare.out new file mode 100644 index 0000000000..5e4294c15d --- /dev/null +++ b/test/JDBC/expected/sp_who-vu-prepare.out @@ -0,0 +1,11 @@ +CREATE LOGIN sp_who_login WITH PASSWORD = 'abc'; +GO + +CREATE TABLE t_sp_who(a INT, colvc30 VARCHAR(30), coldt DATETIME) +go + +CREATE PROCEDURE sp_who_myprocedure AS PRINT 'myprocedure' +go + +CREATE TABLE [sp_who test table] ([test col] INT, d INT) +go diff --git a/test/JDBC/expected/sp_who-vu-verify.out b/test/JDBC/expected/sp_who-vu-verify.out new file mode 100644 index 0000000000..d5bb5cab6d --- /dev/null +++ b/test/JDBC/expected/sp_who-vu-verify.out @@ -0,0 +1,293 @@ +/* tests for sp_babelfish_autoformat */ +sp_babelfish_autoformat 't_sp_who' +go +~~START~~ +varchar#!#varchar#!#varchar +~~END~~ + + +INSERT t_sp_who VALUES (NULL, NULL, NULL) +go +~~ROW COUNT: 1~~ + + +sp_babelfish_autoformat 't_sp_who' +go +~~START~~ +varchar#!#varchar#!#varchar +#!##!# +~~END~~ + + +DELETE t_sp_who +go +~~ROW COUNT: 1~~ + + +INSERT t_sp_who VALUES (1, 'a', cast('01-Feb-2023 11:12:13' AS DATETIME)) +go +~~ROW COUNT: 1~~ + + +sp_babelfish_autoformat 't_sp_who' +go +~~START~~ +varchar#!#varchar#!#varchar +1#!#a#!#2023-02-01 11:12:13 +~~END~~ + + +INSERT t_sp_who VALUES (123456789, 'abcdefghijabcdefghijabcdefghij', cast('02-Jan-2023 11:12:13' AS DATETIME)) +go +~~ROW COUNT: 1~~ + + +sp_babelfish_autoformat 't_sp_who' +go +~~START~~ +varchar#!#varchar#!#varchar + 1#!#a#!#2023-02-01 11:12:13 +123456789#!#abcdefghijabcdefghijabcdefghij#!#2023-01-02 11:12:13 +~~END~~ + + +sp_babelfish_autoformat 't_sp_who', @orderby='order by a desc' +go +~~START~~ +varchar#!#varchar#!#varchar +123456789#!#abcdefghijabcdefghijabcdefghij#!#2023-01-02 11:12:13 + 1#!#a#!#2023-02-01 11:12:13 +~~END~~ + + +sp_babelfish_autoformat 't_sp_who', @orderby='order by a desc', @hiddencols='a' +go +~~START~~ +varchar#!#varchar +abcdefghijabcdefghijabcdefghij#!#2023-01-02 11:12:13 +a#!#2023-02-01 11:12:13 +~~END~~ + + +CREATE TABLE #t(a INT, b INT) +INSERT #t VALUES (1, 98765432) +INSERT #t VALUES (2, NULL) +INSERT #t VALUES (NULL, 345) +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +sp_babelfish_autoformat '#t' +go +~~START~~ +varchar#!#varchar +1#!#98765432 +2#!# +#!# 345 +~~END~~ + + +sp_babelfish_autoformat '[sp_who test table]' +go +~~START~~ +varchar#!#varchar +~~END~~ + + +INSERT [sp_who test table] VALUES (123, 987) +INSERT [sp_who test table] VALUES (1, 454) +go +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + + +sp_babelfish_autoformat '[sp_who test table]', @hiddencols='d' +go +~~START~~ +varchar + 123 + 1 +~~END~~ + + +sp_babelfish_autoformat '[sp_who test table]', @hiddencols='[d]' +go +~~START~~ +varchar + 123 + 1 +~~END~~ + + +sp_babelfish_autoformat '[sp_who test table]', @hiddencols='[test col]' +go +~~START~~ +varchar +987 +454 +~~END~~ + + +sp_babelfish_autoformat '[sp_who test table]', @orderby = 'ORDER by [test col]' +go +~~START~~ +varchar#!#varchar + 1#!#454 + 123#!#987 +~~END~~ + + +sp_babelfish_autoformat '[sp_who test table]', @hiddencols='[test col]', @orderby = 'ORDER BY d' +go +~~START~~ +varchar +454 +987 +~~END~~ + + +/* negative tests */ +sp_babelfish_autoformat NULL +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Must specify table name)~~ + + +sp_babelfish_autoformat '' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Must specify table name)~~ + + +sp_babelfish_autoformat 'nosuchtable' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Table or view 'nosuchtable' not found)~~ + + +sp_babelfish_autoformat 'sp_who_myprocedure' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: 'sp_who_myprocedure' is not a table or view)~~ + + +sp_babelfish_autoformat 't_sp_who', @hiddencols='nosuchcolumn' +go +~~START~~ +varchar#!#varchar#!#varchar + 1#!#a#!#2023-02-01 11:12:13 +123456789#!#abcdefghijabcdefghijabcdefghij#!#2023-01-02 11:12:13 +~~END~~ + + +sp_babelfish_autoformat 't_sp_who', @orderby='a' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: @orderby parameter must start with 'ORDER BY')~~ + + +sp_babelfish_autoformat 't_sp_who', @orderby='order by nosuchcolumn' +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "nosuchcolumn" does not exist)~~ + + +sp_babelfish_autoformat 't_sp_who', @orderby='order by nosuchcolumn', @printrc=0 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "nosuchcolumn" does not exist)~~ + + +sp_babelfish_autoformat 't_sp_who', @orderby='order by nosuchcolumn', @printrc=1 +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: column "nosuchcolumn" does not exist)~~ + + + + +/* tests for sp_who */ +/* + * Since the spid and hostname columns in the output of sp_who have unpredictable values, the tests should avoid showing those. + * Normally, a workaround for this issue is to call the procedure as INSERT..EXECUTE and insert the result set into a table + * and show only the columns that are predictable. + * However, this does not work for procedures where the final SELECT is inside EXECUTE() -- and that is the case for sp_who. + * All of this means we cannot actually run sp_who for the normal use cases + * This test file is created as a .mix file in anticipation of it becoming possible to include full test cases for sp_who + */ +sp_who 0 +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +~~END~~ + + +sp_who '0' +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +~~END~~ + + +sp_who 'sp_who_login' +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +~~END~~ + + +sp_who 'sp_who_login', NULL +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +~~END~~ + + +sp_who 'sp_who_login', '' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Parameter @option can only be 'postgres')~~ + + +-- commenting out this test due to unexpected PG connections showing up +--sp_who 'sp_who_login', 'postgres' +go + +sp_who 'nosuchlogin' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: 'nosuchlogin' is not a valid login or you do not have permission.)~~ + + +sp_who @option=NULL, @loginame='sp_who_login' +go +~~START~~ +varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar +~~END~~ + + +sp_who @option='', @loginame='sp_who_login' +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: Parameter @option can only be 'postgres')~~ + + +-- commenting out this test due to unexpected PG connections showing up +--sp_who @option='postgres', @loginame='sp_who_login' +go diff --git a/test/JDBC/expected/str-vu-verify.out b/test/JDBC/expected/str-vu-verify.out index a325cda21c..346a999cc9 100644 --- a/test/JDBC/expected/str-vu-verify.out +++ b/test/JDBC/expected/str-vu-verify.out @@ -29,7 +29,7 @@ SELECT * FROM str_vu_prepare_v5 GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar -123.0#!#123.5#!#123.5#!#123.0#!#123.0#!#123.0#!#123.5#!#123.5#!#123.0#!#123.0#!#123.5#!#123.5#!#123.5#!#123.5 +123.0#!#123.5#!#123.4#!#123.0#!#123.0#!#123.0#!#123.5#!#123.5#!#123.0#!#123.0#!#123.5#!#123.5#!#123.5#!#123.5 ~~END~~ @@ -197,7 +197,7 @@ EXEC str_vu_prepare_p5 GO ~~START~~ varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar#!#varchar -123.0#!#123.5#!#123.5#!#123.0#!#123.0#!#123.0#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5 +123.0#!#123.5#!#123.4#!#123.0#!#123.0#!#123.0#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5#!#123.5 ~~END~~ diff --git a/test/JDBC/expected/switchoffset-dep-vu-cleanup.out b/test/JDBC/expected/switchoffset-dep-vu-cleanup.out new file mode 100644 index 0000000000..bc337be461 --- /dev/null +++ b/test/JDBC/expected/switchoffset-dep-vu-cleanup.out @@ -0,0 +1,17 @@ +DROP VIEW switchoffset_dep_vu_prepare_v1 +GO + +DROP VIEW switchoffset_dep_vu_prepare_v2 +GO + +DROP PROCEDURE switchoffset_dep_vu_prepare_p1 +GO + +DROP PROCEDURE switchoffset_dep_vu_prepare_p2 +GO + +DROP FUNCTION switchoffset_dep_vu_prepare_f1() +GO + +DROP FUNCTION switchoffset_dep_vu_prepare_f2() +GO diff --git a/test/JDBC/expected/switchoffset-dep-vu-prepare.out b/test/JDBC/expected/switchoffset-dep-vu-prepare.out new file mode 100644 index 0000000000..b39a2e48da --- /dev/null +++ b/test/JDBC/expected/switchoffset-dep-vu-prepare.out @@ -0,0 +1,25 @@ +CREATE VIEW switchoffset_dep_vu_prepare_v1 as (Select switchoffset('2000-04-22 16:2a:51.766890',340)); +GO + +CREATE VIEW switchoffset_dep_vu_prepare_v2 as (Select switchoffset('2000-04-22 ','+12:00')); +GO + +CREATE PROCEDURE switchoffset_dep_vu_prepare_p1 as (SELECT switchoffset(cast('2023-08-08 16:06:45' as datetime2), '-13:00')); +GO + +CREATE PROCEDURE switchoffset_dep_vu_prepare_p2 as (Select switchoffset('2000-04-22 16:23:51',120)); +GO + +CREATE FUNCTION switchoffset_dep_vu_prepare_f1() +RETURNS DATETIMEOFFSET AS +BEGIN +RETURN (Select switchoffset('2000-0a-22 ','+12:00')); +END +GO + +CREATE FUNCTION switchoffset_dep_vu_prepare_f2() +RETURNS DATETIMEOFFSET as +begin +RETURN (Select switchoffset('2000-04-22 16:23:50.76689',120)); +END +GO diff --git a/test/JDBC/expected/switchoffset-dep-vu-verify.out b/test/JDBC/expected/switchoffset-dep-vu-verify.out new file mode 100644 index 0000000000..5c04fbeec0 --- /dev/null +++ b/test/JDBC/expected/switchoffset-dep-vu-verify.out @@ -0,0 +1,47 @@ +SELECT * FROM switchoffset_dep_vu_prepare_v1 +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +SELECT * FROM switchoffset_dep_vu_prepare_v2 +GO +~~START~~ +datetimeoffset +2000-04-22 12:00:00.0000000 +12:00 +~~END~~ + + +EXEC switchoffset_dep_vu_prepare_p1 +GO +~~START~~ +datetimeoffset +2023-08-08 03:06:45.0000000 -13:00 +~~END~~ + + +EXEC switchoffset_dep_vu_prepare_p2 +GO +~~START~~ +datetimeoffset +2000-04-22 18:23:51.0000000 +02:00 +~~END~~ + + +SELECT switchoffset_dep_vu_prepare_f1() +GO +~~START~~ +datetimeoffset +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +SELECT switchoffset_dep_vu_prepare_f2() +GO +~~START~~ +datetimeoffset +2000-04-22 18:23:50.7668900 +02:00 +~~END~~ + diff --git a/test/JDBC/expected/switchoffset.out b/test/JDBC/expected/switchoffset.out new file mode 100644 index 0000000000..bc4ec4a1ad --- /dev/null +++ b/test/JDBC/expected/switchoffset.out @@ -0,0 +1,815 @@ +Select switchoffset('2001-04-22 ', -120) +GO +~~START~~ +datetimeoffset +2001-04-21 22:00:00.0000000 -02:00 +~~END~~ + + +Select switchoffset('2001-04-22 ', 120) +GO +~~START~~ +datetimeoffset +2001-04-22 02:00:00.0000000 +02:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56', 120) +GO +~~START~~ +datetimeoffset +2001-04-22 19:34:56.0000000 +02:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', 120) +GO +~~START~~ +datetimeoffset +2001-04-22 19:34:56.3450000 +02:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', 0) +go +~~START~~ +datetimeoffset +2001-04-22 17:34:56.3450000 +00:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', -0) +go +~~START~~ +datetimeoffset +2001-04-22 17:34:56.3450000 +00:00 +~~END~~ + + +Select switchoffset('200a-0b-22 17:34:56.345', 1) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('2001-04-22 17:34:56.345', 0x12) +go +~~START~~ +datetimeoffset +2001-04-22 17:52:56.3450000 +00:18 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', 'abcd') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset('2001-04-22 ', '+12:00') +GO +~~START~~ +datetimeoffset +2001-04-22 12:00:00.0000000 +12:00 +~~END~~ + + +Select switchoffset('2001-04-22 ', '-12:00') +GO +~~START~~ +datetimeoffset +2001-04-21 12:00:00.0000000 -12:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56', '-12:00') +GO +~~START~~ +datetimeoffset +2001-04-22 05:34:56.0000000 -12:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '-11:00') +GO +~~START~~ +datetimeoffset +2001-04-22 06:34:56.3450000 -11:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '+00:00') +GO +~~START~~ +datetimeoffset +2001-04-22 17:34:56.3450000 +00:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '-00:00') +go +~~START~~ +datetimeoffset +2001-04-22 17:34:56.3450000 +00:00 +~~END~~ + + +Select switchoffset('2001-04-22 10:34:56.345', '-11:00') +go +~~START~~ +datetimeoffset +2001-04-21 23:34:56.3450000 -11:00 +~~END~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '-101:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '-011:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset('200a-0b-22 17:34:56.345', '-011:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '+14:01') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '-14:01') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '-1a:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset('2001-04-22 17:34:56.345', '14:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + + +-- Currently these inputs are giving wrong output due to casting issues .(BABEL-4321) +Select switchoffset(convert(datetime,'2001-04-22'),'-13:00') +GO +~~START~~ +datetimeoffset +2001-04-21 11:00:00.0000000 -13:00 +~~END~~ + + +Select switchoffset(convert(date,'2001-04-22'),'-13:00') +GO +~~START~~ +datetimeoffset +2001-04-21 11:00:00.0000000 -13:00 +~~END~~ + + +Select switchoffset(convert(datetime2,'2001-04-22'),'-13:00') +GO +~~START~~ +datetimeoffset +2001-04-21 11:00:00.0000000 -13:00 +~~END~~ + + +Select switchoffset(convert(smalldatetime,'2001-04-22'),'-13:00') +GO +~~START~~ +datetimeoffset +2001-04-21 11:00:00.0000000 -13:00 +~~END~~ + + + +-- +Select switchoffset('0001-01-00 00:00:00.00', '-10:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('0001-01-01 00:00:00.00', '+13:00') +GO +~~START~~ +datetimeoffset +0001-01-01 13:00:00.0000000 +13:00 +~~END~~ + + +Select switchoffset('9999-12-31 11:59:59.59', '+12:00') +GO +~~START~~ +datetimeoffset +9999-12-31 23:59:59.5900000 +12:00 +~~END~~ + + +Select switchoffset('9999-12-31 24:59:59.59', 130) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('10000-12-31 23:59:59.59', 120) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.050 -8:00' AS datetime2(4)), 120) +GO +~~START~~ +datetimeoffset +1900-05-06 15:59:29.0500000 +02:00 +~~END~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.050 -8:00' AS datetime2(4)), '+12:00') +GO +~~START~~ +datetimeoffset +1900-05-07 01:59:29.0500000 +12:00 +~~END~~ + + +DECLARE @test_date datetime; +SET @test_date = '2022-12-11'; +Select switchoffset(@test_date,'+12:00'); +GO +~~START~~ +datetimeoffset +2022-12-11 12:00:00.0000000 +12:00 +~~END~~ + + +DECLARE @test_date datetime2; +SET @test_date = '2345-12-31 23:59:59.59'; +Select switchoffset(@test_date,-120); +GO +~~START~~ +datetimeoffset +2345-12-31 21:59:59.5900000 -02:00 +~~END~~ + + +Select switchoffset(DATETIME2FROMPARTS(2011, 8, 15, 14, 23, 44, 5, 6 ), 300) +GO +~~START~~ +datetimeoffset +2011-08-15 19:23:44.0000050 +05:00 +~~END~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.998 -8:00' AS datetime2(2)), '+12:00') +Go +~~START~~ +datetimeoffset +1900-05-07 01:59:30.0000000 +12:00 +~~END~~ + + +Select switchoffset('0',120) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('0',0x23) +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +DROP TABLE IF EXISTS tem +GO +Create table tem(a datetimeoffset) +insert into tem (a) values(switchoffset('2000-04-22 12:23:51.766890',120)) +Select * from tem +Select switchoffset(a,'+14:00') from tem; +DROP TABLE IF EXISTS tem +GO +~~ROW COUNT: 1~~ + +~~START~~ +datetimeoffset +2000-04-22 14:23:51.7668900 +02:00 +~~END~~ + +~~START~~ +datetimeoffset +2000-04-23 02:23:51.7668900 +14:00 +~~END~~ + + +Select switchoffset('2030-05-06 13:59:29.998 ' ,'-08:00') + make_interval(1,0,3); +GO +~~START~~ +datetimeoffset +2031-05-27 13:59:29.9980000 -08:00 +~~END~~ + + +Select switchoffset('2030-05-06 13:59:29.998 ' ,'-08:00') - make_interval(1,0,3); +GO +~~START~~ +datetimeoffset +2029-04-15 13:59:29.9980000 -08:00 +~~END~~ + + +Select switchoffset('NULL','NULL') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('NULL',NULL) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset(NULL,NULL) +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select switchoffset(NULL,'NULL') +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.998 -8:00' AS datetime2(2)), 0x23) +GO +~~START~~ +datetimeoffset +1900-05-06 14:34:30.0000000 +00:35 +~~END~~ + + +DECLARE @test_offset text; +SET @test_offset = '-13:00'; +Select switchoffset('2345-12-31 23:59:59.59',@test_offset); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The text, ntext, and image data types are invalid for local variables.)~~ + + +DECLARE @test_offset1 float ; +SET @test_offset1 = 23.567; +Select switchoffset('2345-12-31 23:59:59.59',@test_offset1); +GO +~~START~~ +datetimeoffset +2346-01-01 00:22:59.5900000 +00:23 +~~END~~ + + +DECLARE @test_offset1 decimal ; +SET @test_offset1 = 23.567; +Select switchoffset('2345-12-31 23:59:59.59',@test_offset1); +GO +~~START~~ +datetimeoffset +2346-01-01 00:23:59.5900000 +00:24 +~~END~~ + + +Select switchoffset(CAST('1900-05-0x12 13:59:29.998 -8:00' AS datetime2(2)), 235.67) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: invalid input syntax for type datetime2: "1900-05-0x12 13:59:29.998 -8:00")~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.998 -8:00' AS datetime2(2)), 23647585) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Arithmetic overflow error converting expression to data type smallint.)~~ + + +Select switchoffset('2345-12-31 23:59:59.59',23.567); +GO +~~START~~ +datetimeoffset +2346-01-01 00:22:59.5900000 +00:23 +~~END~~ + + +Select switchoffset('2345-12-31 23:59:59.59',23.467); +GO +~~START~~ +datetimeoffset +2346-01-01 00:22:59.5900000 +00:23 +~~END~~ + + +Select switchoffset('2345-12-31 23:59:59.59',cast(123 as bit)); +GO +~~START~~ +datetimeoffset +2346-01-01 00:00:59.5900000 +00:01 +~~END~~ + + +Select switchoffset('2345-12-31 23:59:59.59',NULL); +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select switchoffset('2345-12-31 23:59:59.59','NULL'); +Go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset(NULL,'+12:00'); +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select switchoffset('NULL','+12:00'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('NULL',234); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset(NULL,234); +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select switchoffset(NULL,'+12:000'); +GO +~~START~~ +datetimeoffset + +~~END~~ + + +Select switchoffset('NULL','+12:000'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('NULL',1233456777888); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset(NULL,1233456777888); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Arithmetic overflow error converting expression to data type smallint.)~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.050 -8:00' AS datetime2(4)), 840) +GO +~~START~~ +datetimeoffset +1900-05-07 03:59:29.0500000 +14:00 +~~END~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.050 -8:00' AS datetime2(4)), 841) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.050 -8:00' AS datetime2(4)), -841) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function todatetimeoffset is invalid.)~~ + + +Select switchoffset(CAST('1900-05-06 13:59:29.050 -8:00' AS datetime2(4)), -840) +GO +~~START~~ +datetimeoffset +1900-05-05 23:59:29.0500000 -14:00 +~~END~~ + + +Select switchoffset(DATETIMEOFFSETFROMPARTS(2011, 8, 15, 14, 30, 00, 500, 12, 30, 3), 0x23) +GO +~~START~~ +datetimeoffset +2011-08-15 02:35:00.5000000 +00:35 +~~END~~ + + +Select switchoffset(DATETIMEOFFSETFROMPARTS(2011, 8, 15, 14, 30, 00, 500, 12, 30, 3), 435.678999) +GO +~~START~~ +datetimeoffset +2011-08-15 09:15:00.5000000 +07:15 +~~END~~ + + +Select switchoffset(DATETIMEOFFSETFROMPARTS(2011, 8, 15, 14, 30, 00, 500, 12, 30, 3), 43) +GO +~~START~~ +datetimeoffset +2011-08-15 02:43:00.5000000 +00:43 +~~END~~ + + +Select switchoffset('1900-05-06 13:59:29.998 -8:00', '-12:00') +GO +~~START~~ +datetimeoffset +1900-05-06 09:59:29.9980000 -12:00 +~~END~~ + + +Select switchoffset('1900-05-06 12:59:29.998 -00:00', '+12:00') +GO +~~START~~ +datetimeoffset +1900-05-07 00:59:29.9980000 +12:00 +~~END~~ + + +Select switchoffset('1900-05-06 12:59:29.998 -02:00', 234) +GO +~~START~~ +datetimeoffset +1900-05-06 18:53:29.9980000 +03:54 +~~END~~ + + +Select switchoffset('1900-05-06 12:59:29.998 +10:00', -456) +GO +~~START~~ +datetimeoffset +1900-05-05 19:23:29.9980000 -07:36 +~~END~~ + + +Select switchoffset('1900-05-06 12:59:29.998 -00:00', 0x12) +GO +~~START~~ +datetimeoffset +1900-05-06 13:17:29.9980000 +00:18 +~~END~~ + + +Select switchoffset(DATETIMEOFFSETFROMPARTS(1, 1, 1, 4, 30, 00, 500, 12, 30, 3), '+00:43') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type datetimeoffset, some of the arguments have values which are not valid.)~~ + + +Select switchoffset('1-1-1 00:00:00.000 +12:00' , '+12:00') +GO +~~START~~ +datetimeoffset +2001-01-01 00:00:00.0000000 +12:00 +~~END~~ + + +Select switchoffset('0001-1-1 00:00:00.000 +12:00' , '+12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('0001-01-01 00:00:00.000 +12:00' , '+12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('0002-01-01 00:00:00.000 +12:00' , '+12:43') +GO +~~START~~ +datetimeoffset +0002-01-01 00:43:00.0000000 +12:43 +~~END~~ + + +Select switchoffset('10000-01-01 00:00:00.000 +12:00' , '+12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('10000-01-01 00:00:00.123 +2:00','+12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('9999-12-31 23:12:00.123 +00:00','+12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.)~~ + + +Select switchoffset('9999-12-31 23:12:00.123 +00:00','+12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.)~~ + + +Select switchoffset('0001-01-01 00:00:01.00 +00:00','+12:00') +GO +~~START~~ +datetimeoffset +0001-01-01 12:00:01.0000000 +12:00 +~~END~~ + + +Select switchoffset('0001-01-01 00:00:00.00 +00:00','+12:00') +GO +~~START~~ +datetimeoffset +0001-01-01 12:00:00.0000000 +12:00 +~~END~~ + + +Select switchoffset('0001-01-01 00:00:01.00 +00:00','+12:00') +GO +~~START~~ +datetimeoffset +0001-01-01 12:00:01.0000000 +12:00 +~~END~~ + + +Select switchoffset(DATETIMEOFFSETFROMPARTS(1, 1, 1, 4, 30, 00, 500, 12, 30, 3), 743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cannot construct data type datetimeoffset, some of the arguments have values which are not valid.)~~ + + +Select switchoffset('1-1-1 00:00:00.000 +12:00' , 743) +GO +~~START~~ +datetimeoffset +2001-01-01 00:23:00.0000000 +12:23 +~~END~~ + + +Select switchoffset('0001-1-1 00:00:00.000 +12:00' , 743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('0001-01-01 00:00:00.000 +12:00' , 743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('0002-01-01 00:00:00.000 +12:00' , 743) +GO +~~START~~ +datetimeoffset +0002-01-01 00:23:00.0000000 +12:23 +~~END~~ + + +Select switchoffset('10000-01-01 00:00:00.000 +12:00' , 743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('10000-01-01 00:00:00.123 +2:00', 743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Conversion failed when converting date and/or time from character string.)~~ + + +Select switchoffset('9999-12-31 23:12:00.123 +00:00',743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.)~~ + + +Select switchoffset('9999-12-31 23:12:00.123 +00:00',743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.)~~ + + +Select switchoffset('0001-01-01 00:00:01.00 +00:00',743) +GO +~~START~~ +datetimeoffset +0001-01-01 12:23:01.0000000 +12:23 +~~END~~ + + +Select switchoffset('0001-01-01 00:00:00.00 +00:00',743) +GO +~~START~~ +datetimeoffset +0001-01-01 12:23:00.0000000 +12:23 +~~END~~ + + +Select switchoffset('0001-01-01 00:00:01.00 +00:00',743) +GO +~~START~~ +datetimeoffset +0001-01-01 12:23:01.0000000 +12:23 +~~END~~ + + +Select switchoffset('0001-01-01 00:00:01.00 +00:00',-743) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.)~~ + + +Select switchoffset('0001-01-01 00:00:01.00 +00:00','-12:00') +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The timezone provided to builtin function switchoffset would cause the datetimeoffset to overflow the range of valid date range in either UTC or local time.)~~ + diff --git a/test/JDBC/expected/sys-all_columns-dep-vu-prepare.out b/test/JDBC/expected/sys-all_columns-dep-vu-prepare.out index 1b9966af3c..eddd22f144 100644 --- a/test/JDBC/expected/sys-all_columns-dep-vu-prepare.out +++ b/test/JDBC/expected/sys-all_columns-dep-vu-prepare.out @@ -11,7 +11,7 @@ CREATE PROCEDURE sys_all_columns_dep_vu_prepare_proc1 AS SELECT name, is_nullable, column_id FROM sys.all_columns - WHERE name in ('sac_int_col1', 'sac_text_col_not_null1'); + WHERE name in ('sac_int_col1', 'sac_text_col_not_null1') ORDER BY name; GO CREATE FUNCTION sys_all_columns_dep_vu_prepare_func1() @@ -25,5 +25,5 @@ CREATE VIEW sys_all_columns_dep_vu_prepare_view1 AS SELECT name, max_length, precision FROM sys.all_columns - WHERE name in ('sac_int_col1', 'sac_text_col_not_null1'); + WHERE name in ('sac_int_col1', 'sac_text_col_not_null1') ORDER BY name; GO diff --git a/test/JDBC/expected/sys-all_sql_modules-vu-verify.out b/test/JDBC/expected/sys-all_sql_modules-vu-verify.out index 445b324e4d..d674ee1bfd 100644 --- a/test/JDBC/expected/sys-all_sql_modules-vu-verify.out +++ b/test/JDBC/expected/sys-all_sql_modules-vu-verify.out @@ -180,6 +180,10 @@ nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#int#!#bit USE master GO +-- reset the login password +ALTER LOGIN sys_all_sql_modules_vu_prepare_user WITH PASSWORD='test' +GO + -- tsql user=sys_all_sql_modules_vu_prepare_user password=test USE sys_all_sql_modules_vu_prepare_db 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/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-dm_exec_connections-dep-vu-verify.out b/test/JDBC/expected/sys-dm_exec_connections-dep-vu-verify.out index 6db030176c..33bca4165a 100644 --- a/test/JDBC/expected/sys-dm_exec_connections-dep-vu-verify.out +++ b/test/JDBC/expected/sys-dm_exec_connections-dep-vu-verify.out @@ -1,3 +1,8 @@ +-- tsql +-- reset the login password +alter login sys_dm_exec_connections_dep_vu_prepare_login with password = 'password' +GO + -- tsql user=sys_dm_exec_connections_dep_vu_prepare_login password=password -- if we query the view not as sysadmin, then we will get an error diff --git a/test/JDBC/expected/sys-dm_exec_connections-vu-verify.out b/test/JDBC/expected/sys-dm_exec_connections-vu-verify.out index debc314e2c..1c1d2f7ee0 100644 --- a/test/JDBC/expected/sys-dm_exec_connections-vu-verify.out +++ b/test/JDBC/expected/sys-dm_exec_connections-vu-verify.out @@ -1,3 +1,8 @@ +-- tsql +-- reset the login password +alter login sys_dm_exec_connections_vu_prepare_login_2296 with password = 'password_2296' +GO + -- tsql user=sys_dm_exec_connections_vu_prepare_login_2296 password=password_2296 -- if we query the view not as sysadmin, then we will get an error select * from sys.dm_exec_connections diff --git a/test/JDBC/expected/sys-dm_exec_sessions-dep-vu-verify.out b/test/JDBC/expected/sys-dm_exec_sessions-dep-vu-verify.out index 10e183eee2..a05b572884 100644 --- a/test/JDBC/expected/sys-dm_exec_sessions-dep-vu-verify.out +++ b/test/JDBC/expected/sys-dm_exec_sessions-dep-vu-verify.out @@ -1,3 +1,8 @@ +-- tsql +-- reset the login password +alter login sys_dm_exec_sessions_dep_vu_prepare_login with password = 'password' +GO + -- tsql user=sys_dm_exec_sessions_dep_vu_prepare_login password=password -- if we query the view not as sysadmin, we will only see info of this session only exec dbo.sys_dm_exec_sessions_dep_vu_prepare_p1 diff --git a/test/JDBC/expected/sys-dm_exec_sessions-vu-verify.out b/test/JDBC/expected/sys-dm_exec_sessions-vu-verify.out index 43f4b5415a..277bde64c0 100644 --- a/test/JDBC/expected/sys-dm_exec_sessions-vu-verify.out +++ b/test/JDBC/expected/sys-dm_exec_sessions-vu-verify.out @@ -1,8 +1,13 @@ --- tsql user=sys_dm_exec_sessions_vu_prepare_login_1887 password=password_1887 +-- tsql -- Some columns have not been queried from the view because either they are not implemented -- yet as part of the sys.dm_exec_sessions view (adding tests for them here is a TODO) -- or their value changes backend to backend +-- reset the login password +alter login sys_dm_exec_sessions_vu_prepare_login_1887 with password = 'password_1887' +go + +-- tsql user=sys_dm_exec_sessions_vu_prepare_login_1887 password=password_1887 -- if we query the view not as sysadmin, we will only see info of this session only select language, client_version, client_interface_name, program_name, date_format, date_first from sys.dm_exec_sessions order by login_name GO diff --git a/test/JDBC/expected/sys-eomonth-vu-cleanup.out b/test/JDBC/expected/sys-eomonth-vu-cleanup.out new file mode 100644 index 0000000000..0a998c56df --- /dev/null +++ b/test/JDBC/expected/sys-eomonth-vu-cleanup.out @@ -0,0 +1,11 @@ +DROP VIEW IF EXISTS EOMONTH_EndOfMonthView; +GO + +DROP PROCEDURE IF EXISTS GetEndOfMonthDate_EOMONTH; +GO + +DROP VIEW IF EXISTS EOMONTH_EndOfNextMonthView; +GO + +DROP PROCEDURE IF EXISTS GetEndOfNextMonthDate_EOMONTH; +GO diff --git a/test/JDBC/expected/sys-eomonth-vu-prepare.out b/test/JDBC/expected/sys-eomonth-vu-prepare.out new file mode 100644 index 0000000000..c0d4683096 --- /dev/null +++ b/test/JDBC/expected/sys-eomonth-vu-prepare.out @@ -0,0 +1,43 @@ +CREATE TABLE EOMONTH_DatesTable ( + Id INT PRIMARY KEY, + DateValue DATE NOT NULL +); +GO + +INSERT INTO EOMONTH_DatesTable (Id, DateValue) +VALUES (1, '1996-01-24'), + (2, '2000-06-15'), + (3, '2022-04-30'); +GO +~~ROW COUNT: 3~~ + + +CREATE PROCEDURE GetEndOfMonthDate_EOMONTH + @Id INT +AS +BEGIN + SELECT EOMONTH(DateValue) AS EndOfMonth + FROM EOMONTH_DatesTable + WHERE Id = @Id; +END; +GO + +CREATE VIEW EOMONTH_EndOfMonthView AS + SELECT Id, DateValue, EOMONTH(DateValue) AS EndOfMonth + FROM EOMONTH_DatesTable +GO + +CREATE VIEW EOMONTH_EndOfNextMonthView AS + SELECT Id, DateValue, EOMONTH(DateValue, 1) AS EndOfNextMonth + FROM EOMONTH_DatesTable +GO + +CREATE PROCEDURE GetEndOfNextMonthDate_EOMONTH + @Id INT + AS + BEGIN + SELECT EOMONTH(DateValue, 1) AS EndOfNextMonth + FROM EOMONTH_DatesTable + WHERE Id = @Id; + END; +GO diff --git a/test/JDBC/expected/sys-eomonth-vu-verify.out b/test/JDBC/expected/sys-eomonth-vu-verify.out new file mode 100644 index 0000000000..82cca7990f --- /dev/null +++ b/test/JDBC/expected/sys-eomonth-vu-verify.out @@ -0,0 +1,424 @@ +SELECT * FROM EOMONTH_EndOfMonthView ORDER BY DateValue ASC; +GO +~~START~~ +int#!#date#!#date +1#!#1996-01-24#!#1996-01-31 +2#!#2000-06-15#!#2000-06-30 +3#!#2022-04-30#!#2022-04-30 +~~END~~ + + +EXEC GetEndOfMonthDate_EOMONTH 1; +GO +~~START~~ +date +1996-01-31 +~~END~~ + + +SELECT * FROM EOMONTH_EndOfNextMonthView ORDER BY DateValue ASC; +GO +~~START~~ +int#!#date#!#date +1#!#1996-01-24#!#1996-02-29 +2#!#2000-06-15#!#2000-07-31 +3#!#2022-04-30#!#2022-05-31 +~~END~~ + + +EXEC GetEndOfNextMonthDate_EOMONTH 1; +GO +~~START~~ +date +1996-02-29 +~~END~~ + + +--Edge case testing: +--when offset is positive edge cases where yyyy can go upto 9999 after that it will throw an error. +SELECT EOMONTH ('2023-05-10',95719) +GO +~~START~~ +date +9999-12-31 +~~END~~ + + +--when offset is positive edge cases where yyyy can go upto 9999 after that it will throw an error. +SELECT EOMONTH ('2023-05-10',95720) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Adding a value to a 'date' column caused an overflow.)~~ + + +--when offset is negative edge cases where yyyy can go upto 0000 after that it will throw an error. +SELECT EOMONTH ('2023-05-10',-24268) +GO +~~START~~ +date +0001-01-31 +~~END~~ + + +--when offset is negative edge cases where yyyy can go upto 0000 after that it will throw an error. +SELECT EOMONTH ('2023-05-10',-24269) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Adding a value to a 'date' column caused an overflow.)~~ + + + +--Lowest Acceptable value 0001 beyond that it will throw an error. +SELECT EOMONTH ('0001-01-31') +GO +~~START~~ +date +0001-01-31 +~~END~~ + + +--Highest Acceptable value 9999 beyond that it will throw an error. +SELECT EOMONTH ('9999-12-31') +GO +~~START~~ +date +9999-12-31 +~~END~~ + + +--Checking for NULL it should return NULL. +SELECT EOMONTH (NULL) +GO +~~START~~ +date + +~~END~~ + + +--Checking for NULL it should return NULL with 2 arguments. +SELECT EOMONTH (NULL,1) +GO +~~START~~ +date + +~~END~~ + + +--Checking for NULL it should return NULL with 2 arguments. +SELECT EOMONTH (NULL,0) +GO +~~START~~ +date + +~~END~~ + + +--Checking for NULL it should return NULL with 2 arguments. +SELECT EOMONTH (NULL,-1) +GO +~~START~~ +date + +~~END~~ + + +--Checking for NULL it should return NULL with 2 arguments. +SELECT EOMONTH (NULL,NULL) +GO +~~START~~ +date + +~~END~~ + + +--Checking if the 1st argument is date and 2nd argument is NULL it should still return the value for that month last date. +SELECT EOMONTH ('1996-01-01',NULL) +GO +~~START~~ +date +1996-01-31 +~~END~~ + + +--BC test cases +--In this test case we are checking if a year is a bc year it should throw an error for BC years. +SELECT EOMONTH('4713-11-24 BC') +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The date exceeds T-SQL compatibility limits.)~~ + + +--In this test case we are checking if it’s the last date of BC it should throw a BC error. After this date the date change to AD. +SELECT EOMONTH('0001-12-31 BC') +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The date exceeds T-SQL compatibility limits.)~~ + + +--In this test case we are checking if it’s the last date of BC. If we add an offset 1 it will give the value as its not a BC year anymore +SELECT EOMONTH('0001-12-31 BC',1) +GO +~~START~~ +date +0001-01-31 +~~END~~ + + +--In this test case we are checking if it’s the last value of AD and if we add an offset of -1 it +--should return an error “Adding a value to a 'date' column caused an overflow.“ because the given input year was not in BC it was AD. +SELECT EOMONTH('0001-01-01',-1) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Adding a value to a 'date' column caused an overflow.)~~ + + +--In this test case we are checking if the year is within T-SQL range and offset is 1 it +--should return an error “Adding a value to a 'date' column caused an overflow.“ because it was within T-SQL range after adding offset it crosses T-SQL range. +SELECT EOMONTH ('9999-12-31',1) +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Adding a value to a 'date' column caused an overflow.)~~ + + +--In this test case we are checking if the year is outside T-SQL range, it should return T-SQL compatibility error. +SELECT EOMONTH ('10000-01-01') +GO +~~START~~ +date +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: The date exceeds T-SQL compatibility limits.)~~ + + +--In this test case we are checking if the year is outside T-SQL range and offset is -1, so after adding offest its within the T-SQL range and it should return the value. +SELECT EOMONTH ('10000-01-01',-1) +GO +~~START~~ +date +9999-12-31 +~~END~~ + + + +--Checking the last date for every month +--Checking if it returns 31 as the last day for January. +SELECT EOMONTH('1996-01-01') +GO +~~START~~ +date +1996-01-31 +~~END~~ + + +--Checking if it returns 29 as the last day for February for leap year. +SELECT EOMONTH('1996-02-20') +GO +~~START~~ +date +1996-02-29 +~~END~~ + + +--Checking if it returns 28 as the last date for February for non-leap year. +SELECT EOMONTH('1997-02-20') +GO +~~START~~ +date +1997-02-28 +~~END~~ + + +--Checking if it returns 31 as the last day for March. +SELECT EOMONTH ('1996-03-20') +GO +~~START~~ +date +1996-03-31 +~~END~~ + + +--Checking if it returns 30 as the last day for April. +SELECT EOMONTH('1996-04-01') +GO +~~START~~ +date +1996-04-30 +~~END~~ + + +--Checking if it returns 31 as the last day for May. +SELECT EOMONTH ('1996-05-20') +GO +~~START~~ +date +1996-05-31 +~~END~~ + + +--Checking if it returns 30 as the last day for June. +SELECT EOMONTH ('1996-06-20') +GO +~~START~~ +date +1996-06-30 +~~END~~ + + +--Checking if it returns 31 as the last day for July. +SELECT EOMONTH ('1996-07-20') +GO +~~START~~ +date +1996-07-31 +~~END~~ + + +--Checking if it returns 31 as the last day for August. +SELECT EOMONTH ('1996-08-20') +GO +~~START~~ +date +1996-08-31 +~~END~~ + + +--Checking if it returns 30 as the last day for September. +SELECT EOMONTH ('1996-09-20') +GO +~~START~~ +date +1996-09-30 +~~END~~ + + +--Checking if it returns 31 as the last day for October. +SELECT EOMONTH ('1996-10-20') +GO +~~START~~ +date +1996-10-31 +~~END~~ + + +--Checking if it returns 30 as the last day for November. +SELECT EOMONTH ('1996-11-20') +GO +~~START~~ +date +1996-11-30 +~~END~~ + + +--Checking if it returns 31 as the last day for December. +SELECT EOMONTH ('1996-12-20') +GO +~~START~~ +date +1996-12-31 +~~END~~ + + + +--If the given offest is 12 and the month is 1, it should increase the year by 1 and month should be January. +SELECT EOMONTH ('1996-01-01',12) +GO +~~START~~ +date +1997-01-31 +~~END~~ + + +--If the given offest is -12 and the month is 1, it should decrease the year by 1 and month should be January. +SELECT EOMONTH ('1996-01-01',-12) +GO +~~START~~ +date +1995-01-31 +~~END~~ + + +--If the given offest is 0, it should just return that month last date. +SELECT EOMONTH ('1996-01-01',0) +GO +~~START~~ +date +1996-01-31 +~~END~~ + + +--If the given is 11 and the month is 1, it should return last day of December. +SELECT EOMONTH ('1996-01-01',11) +GO +~~START~~ +date +1996-12-31 +~~END~~ + + +--If the given offest is -1 and the month is 1, it should decrease the year by 1 and month should be December. +SELECT EOMONTH ('1996-01-01',-1) +GO +~~START~~ +date +1995-12-31 +~~END~~ + + + +--EOMONTH with explicit datetime type +DECLARE @date DATETIME = '12/1/2011'; +SELECT EOMONTH ( @date ) AS Result; +GO +~~START~~ +date +2011-12-31 +~~END~~ + + +--EOMONTH with explicit datetime type and offset +DECLARE @date DATETIME = '12/1/2011'; +SELECT EOMONTH ( @date , 2) AS Result; +GO +~~START~~ +date +2012-02-29 +~~END~~ + + +--EOMONTH with string parameter and implicit conversion +DECLARE @date VARCHAR(255) = '12/1/2011'; +SELECT EOMONTH ( @date ) AS Result; +GO +~~START~~ +date +2011-12-31 +~~END~~ + + +--EOMONTH with string parameter and implicit conversion and offsets +DECLARE @date VARCHAR(255) = '12/1/2011'; +SELECT EOMONTH ( @date , -2) AS Result; +GO +~~START~~ +date +2011-10-31 +~~END~~ + diff --git a/test/JDBC/expected/sys-has_perms_by_name-vu-verify.out b/test/JDBC/expected/sys-has_perms_by_name-vu-verify.out index e78b393790..e370597df7 100644 --- a/test/JDBC/expected/sys-has_perms_by_name-vu-verify.out +++ b/test/JDBC/expected/sys-has_perms_by_name-vu-verify.out @@ -1,3 +1,8 @@ +-- tsql +-- reset the login password +ALTER LOGIN user_perms_by_name WITH PASSWORD='test'; +GO + -- tsql user=user_perms_by_name password=test USE db_perms_by_name; GO 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/sys-parsename-vu-cleanup.out b/test/JDBC/expected/sys-parsename-vu-cleanup.out new file mode 100644 index 0000000000..3011aabc3a --- /dev/null +++ b/test/JDBC/expected/sys-parsename-vu-cleanup.out @@ -0,0 +1,20 @@ +DROP VIEW IF EXISTS parsename_EmployeeDatabaseView1; +GO + +DROP PROCEDURE IF EXISTS parsename_GetEmployeeDatabaseName1; +GO + +DROP VIEW IF EXISTS parsename_EmployeeDatabaseView2; +GO + +DROP PROCEDURE IF EXISTS parsename_GetEmployeeDatabaseName2; +GO + +DROP VIEW IF EXISTS parsename_EmployeeDatabaseView3; +GO + +DROP PROCEDURE IF EXISTS parsename_GetEmployeeDatabaseName3; +GO + +DROP TABLE IF EXISTS parsename_Employee; +GO diff --git a/test/JDBC/expected/sys-parsename-vu-prepare.out b/test/JDBC/expected/sys-parsename-vu-prepare.out new file mode 100644 index 0000000000..769997907d --- /dev/null +++ b/test/JDBC/expected/sys-parsename-vu-prepare.out @@ -0,0 +1,53 @@ +CREATE TABLE parsename_Employee ( + EmployeeID INT PRIMARY KEY, + FirstName NVARCHAR(50), + LastName NVARCHAR(50), + HireDate DATETIME, + Salary MONEY +); +GO + +-- Insert some sample data +INSERT INTO parsename_Employee(EmployeeID, FirstName, LastName, HireDate, Salary) +VALUES (1, 'John', 'Doe', '2020-01-01', 50000), + (2, 'Jane', 'Smith', '2020-02-01', 60000), + (3, 'Bob', 'Johnson', '2020-03-01', 70000); +GO +~~ROW COUNT: 3~~ + + +CREATE VIEW parsename_EmployeeDatabaseView1 +AS +SELECT PARSENAME('tempdb.dbo.Employee', 3) AS [Database Name] +GO + +CREATE PROCEDURE parsename_GetEmployeeDatabaseName1 +AS +BEGIN + SELECT PARSENAME('tempdb.dbo.Employee', 3) AS [Database Name] +END +GO + +CREATE VIEW parsename_EmployeeDatabaseView2 +AS +SELECT PARSENAME('tempdb.dbo.Employee', 2) AS [Schema Name] +GO + +CREATE PROCEDURE parsename_GetEmployeeDatabaseName2 +AS +BEGIN + SELECT PARSENAME('tempdb.dbo.Employee', 2) AS [Schema Name] +END +GO + +CREATE VIEW parsename_EmployeeDatabaseView3 +AS +SELECT PARSENAME('tempdb.dbo.Employee', 1) AS [Table Name] +GO + +CREATE PROCEDURE parsename_GetEmployeeDatabaseName3 +AS +BEGIN +SELECT PARSENAME('tempdb.dbo.Employee_parsename', 1) AS [Table Name] +END +GO diff --git a/test/JDBC/expected/sys-parsename-vu-verify.out b/test/JDBC/expected/sys-parsename-vu-verify.out new file mode 100644 index 0000000000..24a06c0025 --- /dev/null +++ b/test/JDBC/expected/sys-parsename-vu-verify.out @@ -0,0 +1,563 @@ +SELECT PARSENAME('tempdb.dbo.Employee', 3) AS [Database Name], +PARSENAME('tempdb.dbo.Employee', 2) AS [Schema Name], +PARSENAME('tempdb.dbo.Employee', 1) AS [Table Name], +* +FROM +parsename_Employee +ORDER BY HireDate DESC; +GO +~~START~~ +varchar#!#varchar#!#varchar#!#int#!#nvarchar#!#nvarchar#!#datetime#!#money +tempdb#!#dbo#!#Employee#!#3#!#Bob#!#Johnson#!#2020-03-01 00:00:00.0#!#70000.0000 +tempdb#!#dbo#!#Employee#!#2#!#Jane#!#Smith#!#2020-02-01 00:00:00.0#!#60000.0000 +tempdb#!#dbo#!#Employee#!#1#!#John#!#Doe#!#2020-01-01 00:00:00.0#!#50000.0000 +~~END~~ + + +SELECT * FROM parsename_EmployeeDatabaseView1 +GO +~~START~~ +varchar +tempdb +~~END~~ + + +EXEC parsename_GetEmployeeDatabaseName1 +GO +~~START~~ +varchar +tempdb +~~END~~ + + +SELECT * FROM parsename_EmployeeDatabaseView2 +GO +~~START~~ +varchar +dbo +~~END~~ + + +EXEC parsename_GetEmployeeDatabaseName2 +GO +~~START~~ +varchar +dbo +~~END~~ + + +SELECT * FROM parsename_EmployeeDatabaseView3 +GO +~~START~~ +varchar +Employee +~~END~~ + + +EXEC parsename_GetEmployeeDatabaseName3 +GO +~~START~~ +varchar +Employee_parsename +~~END~~ + + +--Checking PARSENAME to return the first part of a four-part name, 'mytable'. +SELECT PARSENAME('tempdb.dbo.Employee.mytable',1) +GO +~~START~~ +varchar +mytable +~~END~~ + + +--Checking PARSENAME to return the second part of a four-part name, 'Employee'. +SELECT PARSENAME('tempdb.dbo.Employee.mytable',2) +GO +~~START~~ +varchar +Employee +~~END~~ + + +--Checking PARSENAME to return the third part of a four-part name, 'dbo'. +SELECT PARSENAME('tempdb.dbo.Employee.mytable',3) +GO +~~START~~ +varchar +dbo +~~END~~ + + +--Checking PARSENAME to the fourth part of a four-part name, 'tempdb'. +SELECT PARSENAME('tempdb.dbo.Employee.mytable',4) +GO +~~START~~ +varchar +tempdb +~~END~~ + + +--Checking PARSENAME to return the fifth part of a four-part name which does not exist. Will return NULL. +SELECT PARSENAME('tempdb.dbo.Employee.mytable',5) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return 'Employee', the first part of a three-part name. +SELECT PARSENAME('tempdb.dbo.Employee',1) +GO +~~START~~ +varchar +Employee +~~END~~ + + +--Checking PARSENAME to return 'dbo', the second part of a three-part name.. +SELECT PARSENAME('tempdb.dbo.Employee',2) +GO +~~START~~ +varchar +dbo +~~END~~ + + +--Checking PARSENAME to return 'tempdb', the third part of a three-part name. +SELECT PARSENAME('tempdb.dbo.Employee',3) +GO +~~START~~ +varchar +tempdb +~~END~~ + + +--Checking PARSENAME to return the fifth part of a three-part name which does not exist. Will return NULL. +SELECT PARSENAME('tempdb.dbo.Employee',5) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return 'Employee', the first part of a three-part name starting with a dot. +SELECT PARSENAME('.dbo.Employee',1) +GO +~~START~~ +varchar +Employee +~~END~~ + + +--Checking PARSENAME to return 'dbo', the second part of a three-part name starting with a dot. +SELECT PARSENAME('.dbo.Employee',2) +GO +~~START~~ +varchar +dbo +~~END~~ + + +--Checking PARSENAME to return NULL, because the third part of a three-part name starting with a dot is not defined. +SELECT PARSENAME('.dbo.Employee',3) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return 'Employee', the first part of a three-part name with no first,second part. +SELECT PARSENAME('..Employee',1) +GO +~~START~~ +varchar +Employee +~~END~~ + + +--Checking PARSENAME to return NULL, because the second part of a three-part name with no second part is not defined. +SELECT PARSENAME('..Employee',2) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return NULL, because the third part of a three-part name with no second and third parts is not defined. +SELECT PARSENAME('..Employee',3) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return NULL, because there's no first part defined in a two-part name with no parts defined. +SELECT PARSENAME('..',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return NULL, because there's no second part defined in a three-part name with no second part. +SELECT PARSENAME('tempdb..Employee',2) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking PARSENAME to return 'tempdb', the third part of a three-part name with no second part. +SELECT PARSENAME('tempdb..Employee',3) +GO +~~START~~ +varchar +tempdb +~~END~~ + + +--Checking PARSENAME to return NULL for the third part of a three-part name starting with a dot. +SELECT PARSENAME('.dbo.Employee',3) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking the third part of a four-part name starting with a dot, which is 'dbo'. +SELECT PARSENAME('.dbo.Employee.table',3) +GO +~~START~~ +varchar +dbo +~~END~~ + + +--Checking for the first part of a four-part name with an empty fourth part, should return NULL. +SELECT PARSENAME('tempdb.dbo.Employee.', 1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if 3 parts are given and object_piece = 2 and the first part is having more than 128 characters so it will should NULL. +SELECT PARSENAME('tempdbvdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd.dbo.Employee',2) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if 3 parts are given and object_piece = 2 and the first part is having than 127 characters so it will return the object_piece value'dbo'. +SELECT PARSENAME('tempdbvddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd.dbo.Employee',2) +GO +~~START~~ +varchar +dbo +~~END~~ + + +--Checking if 3 parts are given and object_piece = 1 and the second part is having more than 128 characters so it will should return NULL. +SELECT PARSENAME('tempdb.dbopdbvdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd.Employee',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if 3 parts are given and object_piece = 1 and the third part is having more than 128 characters so it will should return NULL. +SELECT PARSENAME('tempdb.dbo.Employeeddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',1) +GO +~~START~~ +varchar + +~~END~~ + + +---Checking PARSENAME to return 'Employee' - from a fully bracketed four-part name. +SELECT PARSENAME('[tempdb].[dbo].[Employee]',1) +GO +~~START~~ +varchar +Employee +~~END~~ + + +---Checking PARSENAME to return 'dbo' - from a fully bracketed four-part name. +SELECT PARSENAME('[tempdb].[dbo].[Employee]',2) +GO +~~START~~ +varchar +dbo +~~END~~ + + +---Checking PARSENAME to return 'tempdb' - a fully bracketed four-part name +SELECT PARSENAME('[tempdb].[dbo].[Employee]',3) +GO +~~START~~ +varchar +tempdb +~~END~~ + + +---Checking if inside brackets as [Object_name] and there is an open bracket inside object_name so it should return the value 'Empl[oyee' +SELECT PARSENAME('tempdb.dbo.[Empl[oyee]',1) +GO +~~START~~ +varchar +Empl[oyee +~~END~~ + + +--Checking if inside brackets as [Object_name] and there is an close bracket inside object_name so it should return NULL. +SELECT PARSENAME('tempdb.dbo.[Empl]oyee]',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if inside brackets as [Object_name] and there are 2 close bracket inside object_name so it should escape 1 close bracket and return 'Empl]oyee'. +SELECT PARSENAME('tempdb.dbo.[Empl]]oyee]',1) +GO +~~START~~ +varchar +Empl]oyee +~~END~~ + + +--Checking there is continuous double close brackets inside open and close bracket it should escape one bracket evertime if it encounter a continuous close bracket. +SELECT PARSENAME('tempdb.dbo.[Empl]]oy]]ee]',1) +GO +~~START~~ +varchar +Empl]oy]ee +~~END~~ + + +--Checking if inside brackets as [Object_nam]e but the object name is not properly enclosed so it will return NULL. +SELECT PARSENAME('tempdb.dbo.[Employe]e',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if inside brackets as [Object_name] and there is a double quotes it should return the value 'Empl"oyee'. +SELECT PARSENAME('[tempdb].[dbo].[Empl"oyee]',1) +GO +~~START~~ +varchar +Empl"oyee +~~END~~ + + +--Checking if inside brackets as [Object_name] and there is a double quotes it should return the value 'Empl""oyee'. +SELECT PARSENAME('[tempdb].[dbo].[Empl""oyee]',1) +GO +~~START~~ +varchar +Empl""oyee +~~END~~ + + +--Checking if inside brackets as Ob[ject_name] but the object name is not properly enclosed so it will return NULL. +SELECT PARSENAME('tempdb.dbo.Em[ployee]',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking for syntax error as there is only 1 open bracket. +SELECT PARSENAME('tempdb.dbo.Em[ployee',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking for syntax error as there is only 1 close bracket. +SELECT PARSENAME('tempdb.dbo.Em]ployee',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if inside brackets as [Object_name] and there is a dot it should return 'tempdb.dbo.Employee'. +SELECT PARSENAME('[tempdb.dbo.Employee]',1) +GO +~~START~~ +varchar +tempdb.dbo.Employee +~~END~~ + + +--Checking if inside double quotes as "Object_name" and there is a single double quotes "object"name" so it should return NULL. +SELECT PARSENAME('tempdb.dbo."Emp"loyee"',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if inside double quotes as "Object_name" and there are 2 continuous double quotes "object""name" so it will escape " and it should return 'Emp"loyee'. +SELECT PARSENAME('tempdb.dbo."Emp""loyee"',1) +GO +~~START~~ +varchar +Emp"loyee +~~END~~ + + +--Checking there is continuous double quotes inside a double quotes it should escape one double quotes evertime if it encounter a continuous double quotes. +SELECT PARSENAME('tempdb.dbo."Emp""loy""ee"',1) +GO +~~START~~ +varchar +Emp"loy"ee +~~END~~ + + +--Checking if inside double quotes as "Object_name" and there is a closing bracket it should return the value 'Empl]oyee'. +SELECT PARSENAME('tempdb.dbo."Empl]oyee"',1) +GO +~~START~~ +varchar +Empl]oyee +~~END~~ + + +--Checking if inside double quotes as "Object_name" and there is a closing bracket it should return the value 'Empl]]oyee'. +SELECT PARSENAME('tempdb.dbo."Empl]]oyee"',1) +GO +~~START~~ +varchar +Empl]]oyee +~~END~~ + + +--Checking if inside double quotes as "Object_nam"e but the object name is not properly enclosed so it will return NULL. +SELECT PARSENAME('tempdb.dbo."Employe"e',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking for syntax error as there is only 1 double quotes. +SELECT PARSENAME('tempdb.dbo.Em"ployee',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if inside double quotes as Ob"ject_name" but the object name is not properly enclosed so it will return NULL. +SELECT PARSENAME('tempdb.dbo.Em"ployee"',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking if inside double quotes as "Object_name" and there is a dot it should return 'tempdb.dbo.Employee'. +SELECT PARSENAME('"tempdb.dbo.Employee"',1) +GO +~~START~~ +varchar +tempdb.dbo.Employee +~~END~~ + + +SELECT PARSENAME('AdventureWorksPDW2012.dbo.DimCustomer', 1) AS 'Object Name'; +GO +~~START~~ +varchar +DimCustomer +~~END~~ + + +SELECT PARSENAME('AdventureWorksPDW2012.dbo.DimCustomer', 2) AS 'Schema Name'; +GO +~~START~~ +varchar +dbo +~~END~~ + + +SELECT PARSENAME('AdventureWorksPDW2012.dbo.DimCustomer', 3) AS 'Database Name'; +GO +~~START~~ +varchar +AdventureWorksPDW2012 +~~END~~ + + +SELECT PARSENAME('AdventureWorksPDW2012.dbo.DimCustomer', 4) AS 'Server Name'; +GO +~~START~~ +varchar + +~~END~~ + + +--Checking for very long character input it should return NULL. +SELECT PARSENAME('tempdbvddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddbopdbvdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddEmployeedddddddddddddddddddddddddddtempdbvddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddbopdbvdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddEmployeedddddddddddddddddddddddddddtempdbvddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddbopdbvdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddEmployeedddddddddddddddddddddddddddtempdbvddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddbopdbvdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddEmployeeddddddddddddddddddddddddddd',1) +GO +~~START~~ +varchar + +~~END~~ + + +--128 unicode characters +SELECT PARSENAME('ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡',1) +GO +~~START~~ +varchar +???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? +~~END~~ + + +--129 unicode characters +SELECT PARSENAME('ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡ã¡',1) +GO +~~START~~ +varchar + +~~END~~ + + +--Checking for 0 parts returns NULL +SELECT PARSENAME('',1) +GO +~~START~~ +varchar + +~~END~~ + diff --git a/test/JDBC/expected/sys-server_principals-vu-cleanup.out b/test/JDBC/expected/sys-server_principals-vu-cleanup.out new file mode 100644 index 0000000000..edd947591e --- /dev/null +++ b/test/JDBC/expected/sys-server_principals-vu-cleanup.out @@ -0,0 +1,6 @@ +-- tsql +DROP LOGIN sys_server_principals_vu_login_without_sa +GO + +DROP LOGIN sys_server_principals_vu_login_with_sa +GO diff --git a/test/JDBC/expected/sys-server_principals-vu-prepare.out b/test/JDBC/expected/sys-server_principals-vu-prepare.out new file mode 100644 index 0000000000..0643573604 --- /dev/null +++ b/test/JDBC/expected/sys-server_principals-vu-prepare.out @@ -0,0 +1,6 @@ +-- tsql +CREATE LOGIN sys_server_principals_vu_login_without_sa with password = '123' +GO + +CREATE LOGIN sys_server_principals_vu_login_with_sa with password = '123' +GO diff --git a/test/JDBC/expected/sys-server_principals-vu-verify.out b/test/JDBC/expected/sys-server_principals-vu-verify.out index d2cfd47e2f..db0d7ae665 100644 --- a/test/JDBC/expected/sys-server_principals-vu-verify.out +++ b/test/JDBC/expected/sys-server_principals-vu-verify.out @@ -1,3 +1,7 @@ +-- tsql +ALTER ROLE sysadmin add member sys_server_principals_vu_login_with_sa +GO + SELECT COUNT(*) FROM sys.all_columns WHERE object_id = object_id('sys.server_principals'); GO ~~START~~ @@ -25,3 +29,58 @@ varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit sysadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 ~~END~~ + +-- reset the login password +ALTER LOGIN sys_server_principals_vu_login_without_sa WITH PASSWORD = '123'; +GO + +-- tsql user=sys_server_principals_vu_login_without_sa password=123 +--connect with login which is not a member of sysadmin +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals ORDER BY name +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +sys_server_principals_vu_login_without_sa#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +sysadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +~~END~~ + + +-- psql +ALTER USER sys_server_principals_vu_login_with_sa PASSWORD '123'; +GO + +-- tsql user=sys_server_principals_vu_login_with_sa password=123 +--connect with login which is a member of sysadmin +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals WHERE name = 'jdbc_user'; +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +jdbc_user#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +~~END~~ + + +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals name WHERE name = 'sysadmin'; +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +sysadmin#!#R#!#SERVER_ROLE#!##!#English#!##!#1#!#1 +~~END~~ + + +SELECT name, type, type_desc, default_database_name, default_language_name, credential_id, owning_principal_id, is_fixed_role +FROM sys.server_principals name WHERE name like 'sys_server_principals_vu_login%' ORDER BY name; +GO +~~START~~ +varchar#!#char#!#nvarchar#!#varchar#!#varchar#!#int#!#int#!#bit +sys_server_principals_vu_login_with_sa#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +sys_server_principals_vu_login_without_sa#!#S#!#SQL_LOGIN#!#master#!#English#!#-1#!#-1#!#0 +~~END~~ + + +--tsql +ALTER ROLE sysadmin drop member sys_server_principals_vu_login_with_sa +GO 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..d9ebf317e8 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,16 @@ 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 + +CREATE PROCEDURE sp_databases_dep_vu_prepare_PROC1 +AS +BEGIN + SET NOCOUNT ON; + DECLARE @tmp_sp_addrole TABLE(database_name sys.SYSNAME, database_size int, remarks sys.VARCHAR(254)); + INSERT INTO @tmp_sp_addrole (database_name, database_size, remarks) EXEC sp_databases; + SELECT database_name, (case when database_size >=0 then 1 else NULL end), remarks FROM @tmp_sp_addrole where database_name='sys_sp_databases_dep_vu_prepare_db1'; + SET NOCOUNT OFF; +END +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..524c6d6308 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,15 @@ int select * from sys_sp_databases_dep_vu_prepare_v1 go ~~START~~ +varchar#!#varchar +sys_sp_databases_dep_vu_prepare_db1#!# +~~END~~ + + +EXEC sp_databases_dep_vu_prepare_PROC1 +GO +~~START~~ varchar#!#int#!#varchar -sys_sp_databases_dep_vu_prepare_db1#!#8#!# +sys_sp_databases_dep_vu_prepare_db1#!#1#!# ~~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/expected/sys-sql_expression_dependencies-vu-cleanup.out b/test/JDBC/expected/sys-sql_expression_dependencies-vu-cleanup.out new file mode 100644 index 0000000000..de6ac35be1 --- /dev/null +++ b/test/JDBC/expected/sys-sql_expression_dependencies-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_sql_expression_dependencies_vu_prepare_view +GO + +DROP PROC sys_sql_expression_dependencies_vu_prepare_proc +GO + +DROP FUNCTION sys_sql_expression_dependencies_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys-sql_expression_dependencies-vu-prepare.out b/test/JDBC/expected/sys-sql_expression_dependencies-vu-prepare.out new file mode 100644 index 0000000000..2bfa81e075 --- /dev/null +++ b/test/JDBC/expected/sys-sql_expression_dependencies-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_sql_expression_dependencies_vu_prepare_view AS +SELECT * FROM sys.sql_expression_dependencies +GO + +CREATE PROC sys_sql_expression_dependencies_vu_prepare_proc AS +SELECT * FROM sys.sql_expression_dependencies +GO + +CREATE FUNCTION sys_sql_expression_dependencies_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.sql_expression_dependencies WHERE referencing_id= 1) +END +GO diff --git a/test/JDBC/expected/sys-sql_expression_dependencies-vu-verify.out b/test/JDBC/expected/sys-sql_expression_dependencies-vu-verify.out new file mode 100644 index 0000000000..bc353961c9 --- /dev/null +++ b/test/JDBC/expected/sys-sql_expression_dependencies-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.sql_expression_dependencies +GO +~~START~~ +int#!#int#!#tinyint#!#nvarchar#!#bit#!#tinyint#!#nvarchar#!#varchar#!#varchar#!#varchar#!#varchar#!#int#!#int#!#bit#!#bit +~~END~~ + + +SELECT * FROM sys_sql_expression_dependencies_vu_prepare_view +GO +~~START~~ +int#!#int#!#tinyint#!#nvarchar#!#bit#!#tinyint#!#nvarchar#!#varchar#!#varchar#!#varchar#!#varchar#!#int#!#int#!#bit#!#bit +~~END~~ + + +EXEC sys_sql_expression_dependencies_vu_prepare_proc +GO +~~START~~ +int#!#int#!#tinyint#!#nvarchar#!#bit#!#tinyint#!#nvarchar#!#varchar#!#varchar#!#varchar#!#varchar#!#int#!#int#!#bit#!#bit +~~END~~ + + +SELECT sys_sql_expression_dependencies_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys-sql_modules-vu-verify.out b/test/JDBC/expected/sys-sql_modules-vu-verify.out index 2c101d7d9a..23d51b5506 100644 --- a/test/JDBC/expected/sys-sql_modules-vu-verify.out +++ b/test/JDBC/expected/sys-sql_modules-vu-verify.out @@ -156,6 +156,10 @@ nvarchar#!#bit#!#bit#!#bit#!#bit#!#bit#!#bit#!#int#!#bit USE master GO +-- reset the login password +ALTER LOGIN sys_sql_modules_vu_prepare_user WITH PASSWORD='test' +GO + -- tsql user=sys_sql_modules_vu_prepare_user password=test USE sys_sql_modules_vu_prepare_db 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/expected/sys-systypes-vu-verify.out b/test/JDBC/expected/sys-systypes-vu-verify.out index 52ec9d4e76..7afbaa6c4c 100644 --- a/test/JDBC/expected/sys-systypes-vu-verify.out +++ b/test/JDBC/expected/sys-systypes-vu-verify.out @@ -85,9 +85,33 @@ int ~~END~~ -CREATE TYPE sys_systypes_type FROM int; +-- systypes should also exist in schema "dbo" +SELECT count(*) FROM dbo.systypes WHERE name = 'sys_systypes_type'; +GO +~~START~~ +int +0 +~~END~~ + + +-- Cross-db +SELECT count(*) FROM sys_systypes_db.sys.systypes WHERE name = 'sys_systypes_type'; +GO +~~START~~ +int +1 +~~END~~ + + +SELECT count(*) FROM sys_systypes_db.dbo.systypes WHERE name = 'sys_systypes_type'; GO +~~ERROR (Code: 33557097)~~ +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + + +CREATE TYPE sys_systypes_type FROM int; +GO SELECT name, status, length, variable, allownulls, printfmt, collation FROM sys.systypes WHERE name = 'sys_systypes_type'; GO @@ -97,6 +121,29 @@ sys_systypes_type#!#0#!#4#!#0#!#1#!##!# ~~END~~ +SELECT name, status, length, variable, allownulls, printfmt, collation FROM dbo.systypes WHERE name = 'sys_systypes_type'; +GO +~~START~~ +varchar#!#tinyint#!#smallint#!#bit#!#bit#!#varchar#!#varchar +sys_systypes_type#!#0#!#4#!#0#!#1#!##!# +~~END~~ + + +-- Cross-db +SELECT name, status, length, variable, allownulls, printfmt, collation FROM sys_systypes_db.sys.systypes WHERE name = 'sys_systypes_type'; +GO +~~START~~ +varchar#!#tinyint#!#smallint#!#bit#!#bit#!#varchar#!#varchar +sys_systypes_type#!#0#!#4#!#0#!#1#!##!# +~~END~~ + + +SELECT name, status, length, variable, allownulls, printfmt, collation FROM sys_systypes_db.dbo.systypes WHERE name = 'sys_systypes_type'; +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + DROP TYPE sys_systypes_type; GO diff --git a/test/JDBC/expected/sys-table_types-before-dep-vu-cleanup.out b/test/JDBC/expected/sys-table_types-before-dep-vu-cleanup.out new file mode 100644 index 0000000000..ef0a545b3c --- /dev/null +++ b/test/JDBC/expected/sys-table_types-before-dep-vu-cleanup.out @@ -0,0 +1,6 @@ +drop procedure sys_table_types_dep_vu_prepare_p1 +drop function sys_table_types_dep_vu_prepare_f1 +drop view sys_table_types_dep_vu_prepare_v1 +drop procedure sys_table_types_dep_vu_prepare_p2 +drop type sys_table_types_dep_vu_prepare_tt +GO diff --git a/test/JDBC/expected/sys-table_types-before-dep-vu-prepare.out b/test/JDBC/expected/sys-table_types-before-dep-vu-prepare.out new file mode 100644 index 0000000000..8a8350d4b4 --- /dev/null +++ b/test/JDBC/expected/sys-table_types-before-dep-vu-prepare.out @@ -0,0 +1,23 @@ +-- tsql +create type sys_table_types_dep_vu_prepare_tt as table(sys_table_types_vu_prepare_tt_a int, sys_table_types_vu_prepare_tt_b char); +GO + +create procedure sys_table_types_dep_vu_prepare_p1 as + select count(*) from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt' +GO + +create function sys_table_types_dep_vu_prepare_f1() +returns int +as +begin + return (select count(*) from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt') +end +GO + +create view sys_table_types_dep_vu_prepare_v1 as + select count(*) from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt' +GO + +create procedure sys_table_types_dep_vu_prepare_p2 as + select is_nullable from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt' +GO diff --git a/test/JDBC/expected/sys-table_types-before-dep-vu-verify.out b/test/JDBC/expected/sys-table_types-before-dep-vu-verify.out new file mode 100644 index 0000000000..540b2f3c40 --- /dev/null +++ b/test/JDBC/expected/sys-table_types-before-dep-vu-verify.out @@ -0,0 +1,32 @@ +--tsql +exec sys_table_types_dep_vu_prepare_p1 +GO +~~START~~ +int +1 +~~END~~ + + +select * from sys_table_types_dep_vu_prepare_f1() +GO +~~START~~ +int +1 +~~END~~ + + +select * from sys_table_types_dep_vu_prepare_v1 +GO +~~START~~ +int +1 +~~END~~ + + +exec sys_table_types_dep_vu_prepare_p2 +GO +~~START~~ +bit +0 +~~END~~ + diff --git a/test/JDBC/expected/sys-table_types-dep-vu-cleanup.out b/test/JDBC/expected/sys-table_types-dep-vu-cleanup.out index b591d0dff6..e4a1f7864d 100644 --- a/test/JDBC/expected/sys-table_types-dep-vu-cleanup.out +++ b/test/JDBC/expected/sys-table_types-dep-vu-cleanup.out @@ -1,5 +1,8 @@ drop procedure sys_table_types_dep_vu_prepare_p1 drop function sys_table_types_dep_vu_prepare_f1 drop view sys_table_types_dep_vu_prepare_v1 +drop procedure sys_table_types_dep_vu_prepare_p2 +drop function sys_table_types_dep_vu_prepare_f2 +drop view sys_table_types_dep_vu_prepare_v2 drop type sys_table_types_dep_vu_prepare_tt GO diff --git a/test/JDBC/expected/sys-table_types-dep-vu-prepare.out b/test/JDBC/expected/sys-table_types-dep-vu-prepare.out index 20bfa9efbd..200f65b795 100644 --- a/test/JDBC/expected/sys-table_types-dep-vu-prepare.out +++ b/test/JDBC/expected/sys-table_types-dep-vu-prepare.out @@ -17,3 +17,19 @@ GO create view sys_table_types_dep_vu_prepare_v1 as select count(*) from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt' GO + +create procedure sys_table_types_dep_vu_prepare_p2 as + select is_nullable from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt' +GO + +create view sys_table_types_dep_vu_prepare_v2 as + select is_nullable from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt' +GO + +create function sys_table_types_dep_vu_prepare_f2() +returns sys.bit +as +begin + return (select is_nullable from sys.table_types where name = 'sys_table_types_dep_vu_prepare_tt') +end +GO diff --git a/test/JDBC/expected/sys-table_types-dep-vu-verify.out b/test/JDBC/expected/sys-table_types-dep-vu-verify.out index 6f08278187..75a5151326 100644 --- a/test/JDBC/expected/sys-table_types-dep-vu-verify.out +++ b/test/JDBC/expected/sys-table_types-dep-vu-verify.out @@ -22,3 +22,27 @@ int 1 ~~END~~ + +exec sys_table_types_dep_vu_prepare_p2 +GO +~~START~~ +bit +0 +~~END~~ + + +select * from sys_table_types_dep_vu_prepare_v2 +GO +~~START~~ +bit +0 +~~END~~ + + +select * from sys_table_types_dep_vu_prepare_f2() +GO +~~START~~ +bit +0 +~~END~~ + diff --git a/test/JDBC/expected/sys-table_types-vu-verify.out b/test/JDBC/expected/sys-table_types-vu-verify.out index 9a1572aaaf..7a009f0410 100644 --- a/test/JDBC/expected/sys-table_types-vu-verify.out +++ b/test/JDBC/expected/sys-table_types-vu-verify.out @@ -18,7 +18,7 @@ from sys.table_types where name = 'sys_table_types_vu_prepare_tt'; GO ~~START~~ -text#!#int#!#int#!#smallint#!#int#!#int#!#varchar#!#int#!#int#!#int#!#int#!#int#!#int#!#bit +text#!#int#!#int#!#smallint#!#int#!#int#!#varchar#!#bit#!#int#!#int#!#int#!#int#!#int#!#bit sys_table_types_vu_prepare_tt#!#0#!##!#-1#!#0#!#0#!##!#0#!#1#!#0#!#0#!#0#!#1#!#0 ~~END~~ diff --git a/test/JDBC/expected/sys-table_types.out b/test/JDBC/expected/sys-table_types.out index a97ed4f775..c4f34b547a 100644 --- a/test/JDBC/expected/sys-table_types.out +++ b/test/JDBC/expected/sys-table_types.out @@ -22,7 +22,7 @@ from sys.table_types where name = 'tt_type'; GO ~~START~~ -text#!#int#!#int#!#smallint#!#int#!#int#!#varchar#!#int#!#int#!#int#!#int#!#int#!#int#!#bit +text#!#int#!#int#!#smallint#!#int#!#int#!#varchar#!#bit#!#int#!#int#!#int#!#int#!#int#!#bit tt_type#!#0#!##!#-1#!#0#!#0#!##!#0#!#1#!#0#!#0#!#0#!#1#!#0 ~~END~~ diff --git a/test/JDBC/expected/sys-types-before-dep-vu-cleanup.out b/test/JDBC/expected/sys-types-before-dep-vu-cleanup.out new file mode 100644 index 0000000000..f5b7574a70 --- /dev/null +++ b/test/JDBC/expected/sys-types-before-dep-vu-cleanup.out @@ -0,0 +1,2 @@ +DROP DATABASE sys_types_dep_vu_prepare_db1 +GO diff --git a/test/JDBC/expected/sys-types-before-dep-vu-prepare.out b/test/JDBC/expected/sys-types-before-dep-vu-prepare.out new file mode 100644 index 0000000000..a0e538eb74 --- /dev/null +++ b/test/JDBC/expected/sys-types-before-dep-vu-prepare.out @@ -0,0 +1,40 @@ +CREATE DATABASE sys_types_dep_vu_prepare_db1; +GO + +USE sys_types_dep_vu_prepare_db1 +GO + +CREATE TYPE sys_types_dep_vu_prepare_ty1 FROM int +GO + +CREATE PROCEDURE sys_types_dep_vu_prepare_p1 AS + SELECT count(*) FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' +GO + +CREATE FUNCTION sys_types_dep_vu_prepare_f1() +RETURNS INT +AS +BEGIN + RETURN (SELECT count(*) FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1') +END +GO + +CREATE VIEW sys_types_dep_vu_prepare_v1 AS + SELECT count(*) FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' +GO + +CREATE VIEW sys_types_dep_vu_prepare_v2 AS + SELECT is_nullable FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' +GO + +CREATE PROCEDURE sys_types_dep_vu_prepare_p2 AS + SELECT is_nullable FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' +GO + +CREATE FUNCTION sys_types_dep_vu_prepare_f2() +RETURNS sys.bit +AS +BEGIN + RETURN (SELECT is_nullable FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1') +END +GO diff --git a/test/JDBC/expected/sys-types-before-dep-vu-verify.out b/test/JDBC/expected/sys-types-before-dep-vu-verify.out new file mode 100644 index 0000000000..328eccb312 --- /dev/null +++ b/test/JDBC/expected/sys-types-before-dep-vu-verify.out @@ -0,0 +1,50 @@ +USE sys_types_dep_vu_prepare_db1 +GO + +EXEC sys_types_dep_vu_prepare_p1 +GO +~~START~~ +int +1 +~~END~~ + + +SELECT * FROM sys_types_dep_vu_prepare_f1() +GO +~~START~~ +int +1 +~~END~~ + + +SELECT * FROM sys_types_dep_vu_prepare_v1 +GO +~~START~~ +int +1 +~~END~~ + + +EXEC sys_types_dep_vu_prepare_p2 +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT * FROM sys_types_dep_vu_prepare_v2 +GO +~~START~~ +int +1 +~~END~~ + + +SELECT * FROM sys_types_dep_vu_prepare_f2() +GO +~~START~~ +bit +1 +~~END~~ + diff --git a/test/JDBC/expected/sys-types-dep-vu-prepare.out b/test/JDBC/expected/sys-types-dep-vu-prepare.out index b42877e088..a0e538eb74 100644 --- a/test/JDBC/expected/sys-types-dep-vu-prepare.out +++ b/test/JDBC/expected/sys-types-dep-vu-prepare.out @@ -23,3 +23,18 @@ CREATE VIEW sys_types_dep_vu_prepare_v1 AS SELECT count(*) FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' GO +CREATE VIEW sys_types_dep_vu_prepare_v2 AS + SELECT is_nullable FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' +GO + +CREATE PROCEDURE sys_types_dep_vu_prepare_p2 AS + SELECT is_nullable FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1' +GO + +CREATE FUNCTION sys_types_dep_vu_prepare_f2() +RETURNS sys.bit +AS +BEGIN + RETURN (SELECT is_nullable FROM sys.types WHERE name = 'sys_types_dep_vu_prepare_ty1') +END +GO diff --git a/test/JDBC/expected/sys-types-dep-vu-verify.out b/test/JDBC/expected/sys-types-dep-vu-verify.out index 44b3224b58..5df1cae91a 100644 --- a/test/JDBC/expected/sys-types-dep-vu-verify.out +++ b/test/JDBC/expected/sys-types-dep-vu-verify.out @@ -24,3 +24,27 @@ int 1 ~~END~~ + +EXEC sys_types_dep_vu_prepare_p2 +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT * FROM sys_types_dep_vu_prepare_v2 +GO +~~START~~ +bit +1 +~~END~~ + + +SELECT * FROM sys_types_dep_vu_prepare_f2() +GO +~~START~~ +bit +1 +~~END~~ + 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/expected/sys-userid-vu-cleanup.out b/test/JDBC/expected/sys-userid-vu-cleanup.out new file mode 100644 index 0000000000..5cc9608eeb --- /dev/null +++ b/test/JDBC/expected/sys-userid-vu-cleanup.out @@ -0,0 +1,41 @@ +DROP VIEW view_current_principal_id; +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 + +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/sys-userid-vu-prepare.out b/test/JDBC/expected/sys-userid-vu-prepare.out new file mode 100644 index 0000000000..a4a56dff20 --- /dev/null +++ b/test/JDBC/expected/sys-userid-vu-prepare.out @@ -0,0 +1,63 @@ +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 + SELECT user_name(DATABASE_PRINCIPAL_ID()); +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 + +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/sys-userid-vu-verify.out b/test/JDBC/expected/sys-userid-vu-verify.out new file mode 100644 index 0000000000..c9ffe4edcb --- /dev/null +++ b/test/JDBC/expected/sys-userid-vu-verify.out @@ -0,0 +1,176 @@ +SELECT * FROM view_current_principal_id; +GO +~~START~~ +nvarchar +dbo +~~END~~ + + +EXEC proc_current_principal_id; +GO +~~START~~ +nvarchar +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~~ +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~~ + + +SELECT (DATABASE_PRINCIPAL_ID(NULL)); +GO +~~START~~ +int + +~~END~~ + + +SELECT user_name(DATABASE_PRINCIPAL_ID('db_owner ')); +GO +~~START~~ +nvarchar +db_owner +~~END~~ + + +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/sys_asymmetric_keys-vu-cleanup.out b/test/JDBC/expected/sys_asymmetric_keys-vu-cleanup.out new file mode 100644 index 0000000000..3a7726a947 --- /dev/null +++ b/test/JDBC/expected/sys_asymmetric_keys-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_asymmetric_keys_vu_prepare_view +GO + +DROP PROC sys_asymmetric_keys_vu_prepare_proc +GO + +DROP FUNCTION sys_asymmetric_keys_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys_asymmetric_keys-vu-prepare.out b/test/JDBC/expected/sys_asymmetric_keys-vu-prepare.out new file mode 100644 index 0000000000..b344c237cd --- /dev/null +++ b/test/JDBC/expected/sys_asymmetric_keys-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_asymmetric_keys_vu_prepare_view AS +SELECT * FROM sys.asymmetric_keys +GO + +CREATE PROC sys_asymmetric_keys_vu_prepare_proc AS +SELECT * FROM sys.asymmetric_keys +GO + +CREATE FUNCTION sys_asymmetric_keys_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.asymmetric_keys WHERE key_length= 0) +END +GO diff --git a/test/JDBC/expected/sys_asymmetric_keys-vu-verify.out b/test/JDBC/expected/sys_asymmetric_keys-vu-verify.out new file mode 100644 index 0000000000..fe7e470272 --- /dev/null +++ b/test/JDBC/expected/sys_asymmetric_keys-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.asymmetric_keys +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#varbinary#!#char#!#nvarchar#!#int#!#varbinary#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#uniqueidentifier#!#sql_variant +~~END~~ + + +SELECT * FROM sys_asymmetric_keys_vu_prepare_view +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#varbinary#!#char#!#nvarchar#!#int#!#varbinary#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#uniqueidentifier#!#sql_variant +~~END~~ + + +EXEC sys_asymmetric_keys_vu_prepare_proc +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#varbinary#!#char#!#nvarchar#!#int#!#varbinary#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#uniqueidentifier#!#sql_variant +~~END~~ + + +SELECT sys_asymmetric_keys_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys_babelfish_configurations_view-vu-verify.out b/test/JDBC/expected/sys_babelfish_configurations_view-vu-verify.out index 013ccf0d53..3acde3ea4a 100644 --- a/test/JDBC/expected/sys_babelfish_configurations_view-vu-verify.out +++ b/test/JDBC/expected/sys_babelfish_configurations_view-vu-verify.out @@ -2,7 +2,7 @@ SELECT * FROM sys_babelfish_configurations_view_vu_prepare_view GO ~~START~~ int -39 +42 ~~END~~ @@ -10,7 +10,7 @@ EXEC sys_babelfish_configurations_view_vu_prepare_proc GO ~~START~~ int -39 +42 ~~END~~ @@ -18,7 +18,7 @@ SELECT * FROM sys_babelfish_configurations_view_vu_prepare_func() GO ~~START~~ int -39 +42 ~~END~~ diff --git a/test/JDBC/expected/sys_certificates-vu-cleanup.out b/test/JDBC/expected/sys_certificates-vu-cleanup.out new file mode 100644 index 0000000000..e3fc7bb825 --- /dev/null +++ b/test/JDBC/expected/sys_certificates-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_certificates_vu_prepare_view +GO + +DROP PROC sys_certificates_vu_prepare_proc +GO + +DROP FUNCTION sys_certificates_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys_certificates-vu-prepare.out b/test/JDBC/expected/sys_certificates-vu-prepare.out new file mode 100644 index 0000000000..9bdf0789f0 --- /dev/null +++ b/test/JDBC/expected/sys_certificates-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_certificates_vu_prepare_view AS +SELECT * FROM sys.certificates +GO + +CREATE PROC sys_certificates_vu_prepare_proc AS +SELECT * FROM sys.certificates +GO + +CREATE FUNCTION sys_certificates_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.certificates WHERE key_length = 0) +END +GO diff --git a/test/JDBC/expected/sys_certificates-vu-verify.out b/test/JDBC/expected/sys_certificates-vu-verify.out new file mode 100644 index 0000000000..3327a085be --- /dev/null +++ b/test/JDBC/expected/sys_certificates-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.certificates +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#bit#!#nvarchar#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#varbinary#!#nvarchar#!#datetime#!#int +~~END~~ + + +SELECT * FROM sys_certificates_vu_prepare_view +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#bit#!#nvarchar#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#varbinary#!#nvarchar#!#datetime#!#int +~~END~~ + + +EXEC sys_certificates_vu_prepare_proc +GO +~~START~~ +varchar#!#int#!#int#!#char#!#nvarchar#!#bit#!#nvarchar#!#nvarchar#!#varbinary#!#nvarchar#!#nvarchar#!#datetime#!#datetime#!#varbinary#!#nvarchar#!#datetime#!#int +~~END~~ + + +SELECT sys_certificates_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys_database_permissions-vu-cleanup.out b/test/JDBC/expected/sys_database_permissions-vu-cleanup.out new file mode 100644 index 0000000000..fcb93d412c --- /dev/null +++ b/test/JDBC/expected/sys_database_permissions-vu-cleanup.out @@ -0,0 +1,11 @@ +USE master +GO + +DROP VIEW sys_database_permissions_vu_prepare_view +GO + +DROP PROC sys_database_permissions_vu_prepare_proc +GO + +DROP FUNCTION sys_database_permissions_vu_prepare_func +GO diff --git a/test/JDBC/expected/sys_database_permissions-vu-prepare.out b/test/JDBC/expected/sys_database_permissions-vu-prepare.out new file mode 100644 index 0000000000..0276a4581d --- /dev/null +++ b/test/JDBC/expected/sys_database_permissions-vu-prepare.out @@ -0,0 +1,18 @@ +USE master +GO + +CREATE VIEW sys_database_permissions_vu_prepare_view AS +SELECT * FROM sys.database_permissions +GO + +CREATE PROC sys_database_permissions_vu_prepare_proc AS +SELECT * FROM sys.database_permissions +GO + +CREATE FUNCTION sys_database_permissions_vu_prepare_func() +RETURNS INT +AS +BEGIN + RETURN (SELECT COUNT(*) FROM sys.database_permissions WHERE state='A') +END +GO diff --git a/test/JDBC/expected/sys_database_permissions-vu-verify.out b/test/JDBC/expected/sys_database_permissions-vu-verify.out new file mode 100644 index 0000000000..83fbd0207d --- /dev/null +++ b/test/JDBC/expected/sys_database_permissions-vu-verify.out @@ -0,0 +1,31 @@ +USE master +GO + +SELECT * FROM sys.database_permissions +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#int#!#int#!#char#!#nvarchar#!#char#!#nvarchar +~~END~~ + + +SELECT * FROM sys_database_permissions_vu_prepare_view +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#int#!#int#!#char#!#nvarchar#!#char#!#nvarchar +~~END~~ + + +EXEC sys_database_permissions_vu_prepare_proc +GO +~~START~~ +tinyint#!#nvarchar#!#int#!#int#!#int#!#int#!#char#!#nvarchar#!#char#!#nvarchar +~~END~~ + + +SELECT sys_database_permissions_vu_prepare_func() +GO +~~START~~ +int +0 +~~END~~ + diff --git a/test/JDBC/expected/sys_server_role_members-vu-cleanup.out b/test/JDBC/expected/sys_server_role_members-vu-cleanup.out new file mode 100644 index 0000000000..3ec3cdb173 --- /dev/null +++ b/test/JDBC/expected/sys_server_role_members-vu-cleanup.out @@ -0,0 +1,26 @@ +DROP LOGIN sys_server_role_members_vu_prepare_login1; +GO + +DROP LOGIN sys_server_role_members_vu_prepare_login2; +GO + +DROP LOGIN sys_server_role_members_vu_prepare_login3; +GO + +DROP LOGIN sys_server_role_members_vu_prepare_login4; +GO + +DROP VIEW sys_server_role_members_vu_prepare_view; +GO + +DROP FUNCTION sys_server_role_members_vu_prepare_func; +GO + +DROP PROCEDURE sys_server_role_members_vu_prepare_proc; +GO + +DROP USER sys_server_role_members_vu_prepare_without_sa; +GO + +DROP LOGIN sys_server_role_members_vu_prepare_without_sa; +GO diff --git a/test/JDBC/expected/sys_server_role_members-vu-prepare.out b/test/JDBC/expected/sys_server_role_members-vu-prepare.out new file mode 100644 index 0000000000..d997ec6590 --- /dev/null +++ b/test/JDBC/expected/sys_server_role_members-vu-prepare.out @@ -0,0 +1,58 @@ +-- tsql +CREATE LOGIN sys_server_role_members_vu_prepare_login1 WITH PASSWORD = '123'; +GO + +CREATE LOGIN sys_server_role_members_vu_prepare_login2 WITH PASSWORD = '123'; +GO + +CREATE LOGIN sys_server_role_members_vu_prepare_login3 WITH PASSWORD = '123'; +GO + +CREATE LOGIN sys_server_role_members_vu_prepare_login4 WITH PASSWORD = '123'; +GO + +CREATE LOGIN sys_server_role_members_vu_prepare_without_sa WITH PASSWORD = '123'; +GO + +CREATE USER sys_server_role_members_vu_prepare_without_sa for login sys_server_role_members_vu_prepare_without_sa; +GO + +CREATE VIEW sys_server_role_members_vu_prepare_view AS +SELECT +roles.name AS RolePrincipalName +, members.name AS MemberPrincipalName +FROM sys.server_role_members AS server_role_members +INNER JOIN sys.server_principals AS roles + ON server_role_members.role_principal_id = roles.principal_id +INNER JOIN sys.server_principals AS members + ON server_role_members.member_principal_id = members.principal_id order by MemberPrincipalName; +GO + +CREATE FUNCTION sys_server_role_members_vu_prepare_func () +RETURNS TABLE +AS +RETURN ( + SELECT + roles.name AS RolePrincipalName + , members.name AS MemberPrincipalName + FROM sys.server_role_members AS server_role_members + INNER JOIN sys.server_principals AS roles + ON server_role_members.role_principal_id = roles.principal_id + INNER JOIN sys.server_principals AS members + ON server_role_members.member_principal_id = members.principal_id order by MemberPrincipalName + ); +GO + +CREATE PROCEDURE sys_server_role_members_vu_prepare_proc +AS +BEGIN + SELECT + roles.name AS RolePrincipalName + , members.name AS MemberPrincipalName + FROM sys.server_role_members AS server_role_members + INNER JOIN sys.server_principals AS roles + ON server_role_members.role_principal_id = roles.principal_id + INNER JOIN sys.server_principals AS members + ON server_role_members.member_principal_id = members.principal_id order by MemberPrincipalName; +END; +GO diff --git a/test/JDBC/expected/sys_server_role_members-vu-verify.out b/test/JDBC/expected/sys_server_role_members-vu-verify.out new file mode 100644 index 0000000000..863b2df109 --- /dev/null +++ b/test/JDBC/expected/sys_server_role_members-vu-verify.out @@ -0,0 +1,146 @@ +-- tsql +SELECT * from sys_server_role_members_vu_prepare_view; +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +~~END~~ + + +ALTER SERVER ROLE sysadmin ADD MEMBER sys_server_role_members_vu_prepare_login1; +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER sys_server_role_members_vu_prepare_login2; +GO + +SELECT * from sys_server_role_members_vu_prepare_view; +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +sysadmin#!#sys_server_role_members_vu_prepare_login1 +sysadmin#!#sys_server_role_members_vu_prepare_login2 +~~END~~ + + +ALTER SERVER ROLE sysadmin ADD MEMBER sys_server_role_members_vu_prepare_login3; +GO + +SELECT * from sys_server_role_members_vu_prepare_view; +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +sysadmin#!#sys_server_role_members_vu_prepare_login1 +sysadmin#!#sys_server_role_members_vu_prepare_login2 +sysadmin#!#sys_server_role_members_vu_prepare_login3 +~~END~~ + + +--granting access to user +GRANT SELECT ON sys_server_role_members_vu_prepare_view TO sys_server_role_members_vu_prepare_without_sa; +GO + +GRANT EXECUTE ON sys_server_role_members_vu_prepare_proc TO sys_server_role_members_vu_prepare_without_sa; +GO + +GRANT EXECUTE ON sys_server_role_members_vu_prepare_func TO sys_server_role_members_vu_prepare_without_sa; +GO + +-- reset the login password +ALTER LOGIN sys_server_role_members_vu_prepare_without_sa WITH PASSWORD = '123'; +GO + +-- tsql user=sys_server_role_members_vu_prepare_without_sa password=123 + +SELECT * FROM sys_server_role_members_vu_prepare_view; +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +~~END~~ + + +EXEC sys_server_role_members_vu_prepare_proc +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +~~END~~ + + +SELECT * FROM sys_server_role_members_vu_prepare_func(); +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +~~END~~ + + +-- psql +ALTER USER sys_server_role_members_vu_prepare_login1 PASSWORD '123'; +GO + +-- tsql user=sys_server_role_members_vu_prepare_login1 password=123 +SELECT * from sys_server_role_members_vu_prepare_view; +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +sysadmin#!#sys_server_role_members_vu_prepare_login1 +sysadmin#!#sys_server_role_members_vu_prepare_login2 +sysadmin#!#sys_server_role_members_vu_prepare_login3 +~~END~~ + + +EXEC sys_server_role_members_vu_prepare_proc +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +sysadmin#!#sys_server_role_members_vu_prepare_login1 +sysadmin#!#sys_server_role_members_vu_prepare_login2 +sysadmin#!#sys_server_role_members_vu_prepare_login3 +~~END~~ + + +SELECT * FROM sys_server_role_members_vu_prepare_func(); +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +sysadmin#!#sys_server_role_members_vu_prepare_login1 +sysadmin#!#sys_server_role_members_vu_prepare_login2 +sysadmin#!#sys_server_role_members_vu_prepare_login3 +~~END~~ + + +-- tsql +ALTER SERVER ROLE sysadmin DROP MEMBER sys_server_role_members_vu_prepare_login1; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER sys_server_role_members_vu_prepare_login2; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER sys_server_role_members_vu_prepare_login3; +GO + +ALTER SERVER ROLE sysadmin DROP MEMBER sys_server_role_members_vu_prepare_login4; +GO + +EXEC sys_server_role_members_vu_prepare_proc +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +~~END~~ + + +SELECT * FROM sys_server_role_members_vu_prepare_func(); +GO +~~START~~ +varchar#!#varchar +sysadmin#!#jdbc_user +~~END~~ + + 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..fc822bb5f7 --- /dev/null +++ b/test/JDBC/expected/sys_syslogins_dep-vu-cleanup.out @@ -0,0 +1,23 @@ +DROP DATABASE sys_syslogins_dep_vu_prepare_db +GO + +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..2310aa4eec --- /dev/null +++ b/test/JDBC/expected/sys_syslogins_dep-vu-prepare.out @@ -0,0 +1,35 @@ +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 + +CREATE DATABASE sys_syslogins_dep_vu_prepare_db +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..29a35c6f0a --- /dev/null +++ b/test/JDBC/expected/sys_syslogins_dep-vu-verify.out @@ -0,0 +1,174 @@ +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~~ + + +-- syslogins should also present in dbo schema +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 dbo.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~~ + + +-- Cross-db check for syslogins +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_dep_vu_prepare_db.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~~ + + +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_dep_vu_prepare_db.dbo.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~~ + + +SELECT loginname, dbname, sysadmin from syslogins where loginname = 'sysadmin' +GO +~~START~~ +nvarchar#!#varchar#!#int +~~END~~ + + +-- adding alter serverrole cases here because it cant go to prepare +CREATE LOGIN sys_syslogins_dep_vu_prepare_login3 WITH PASSWORD = '12345' +GO + +ALTER SERVER ROLE sysadmin ADD MEMBER sys_syslogins_dep_vu_prepare_login3 +GO + +SELECT loginname,dbname,sysadmin from syslogins WHERE name LIKE '%sys_syslogins_dep_vu_prepare%' ORDER BY name +GO +~~START~~ +nvarchar#!#varchar#!#int +sys_syslogins_dep_vu_prepare_login1#!#master#!#0 +sys_syslogins_dep_vu_prepare_login2#!#master#!#0 +sys_syslogins_dep_vu_prepare_login3#!#master#!#1 +~~END~~ + + +ALTER SERVER ROLE sysadmin DROP MEMBER sys_syslogins_dep_vu_prepare_login3 +GO + +DROP LOGIN sys_syslogins_dep_vu_prepare_login3 +GO + +-- 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~~ + + +-- syslogins should also present in dbo schema +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 dbo.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~~ + + +-- Cross-db check for syslogins +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_dep_vu_prepare_db.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~~ + + +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_dep_vu_prepare_db.dbo.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/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..b6b1b14225 --- /dev/null +++ b/test/JDBC/expected/sys_sysusers_dep-vu-verify.out @@ -0,0 +1,217 @@ +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~~ + + +-- sysusers should also exist in schema "dbo" +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM dbo.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~~ + + +SELECT name, hasdbaccess, islogin +FROM dbo.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~~ + + +SELECT name, hasdbaccess, islogin +FROM dbo.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~~ + + +SELECT name, hasdbaccess, islogin +FROM dbo.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~~ + + +SELECT name, hasdbaccess, islogin +FROM dbo.sysusers +WHERE name = 'sysusers_dep_vu_prepare_user1' +GO +~~START~~ +varchar#!#int#!#int +sysusers_dep_vu_prepare_user1#!#1#!#1 +~~END~~ + + +USE master +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 +~~START~~ +varchar#!#int#!#int#!#int#!#int#!#int +dbo#!#1#!#1#!#0#!#1#!#0 +guest#!#1#!#1#!#0#!#1#!#0 +~~END~~ + + +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM dbo.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#!#1#!#1#!#0#!#1#!#0 +~~END~~ + + +-- Cross-db +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sysusersdb.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~~ + + +SELECT name, hasdbaccess, islogin, isntname, issqluser, issqlrole +FROM sysusersdb.dbo.sysusers +WHERE name LIKE '%sysusers_dep_vu_prepare_%' OR name = 'dbo' or name = 'guest' +ORDER BY name +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Cross-DB system view query is not currently supported in Babelfish.)~~ + diff --git a/test/JDBC/expected/table-variable-psql.out b/test/JDBC/expected/table-variable-psql.out new file mode 100644 index 0000000000..d168f4d13d --- /dev/null +++ b/test/JDBC/expected/table-variable-psql.out @@ -0,0 +1,28 @@ +-- psql +set babelfishpg_tsql.sql_dialect = "tsql"; +GO + +create type tableType as table( + a text not null, + b int primary key, + c int); +GO + +create procedure itvf8_proc as +begin + declare @tableVariable tableType + insert into @tableVariable values('hello1', 1, 1001) + insert into @tableVariable values('hello2', 2, 1002) + update @tableVariable set a = 'hello1_v2' where b = 1 +end; +GO + +-- should be clean and no error +CALL itvf8_proc(); +GO + +DROP PROCEDURE itvf8_proc; +GO + +DROP TYPE tableType; +GO diff --git a/test/JDBC/expected/table-variable-vu-cleanup.out b/test/JDBC/expected/table-variable-vu-cleanup.out index 0f51fcf5bf..0ca455f18b 100644 --- a/test/JDBC/expected/table-variable-vu-cleanup.out +++ b/test/JDBC/expected/table-variable-vu-cleanup.out @@ -59,3 +59,13 @@ drop schema table_variable_vu_schema go drop function table_variable_vu_func2 go + +-- BABEL-4337 - nested tv +DROP FUNCTION tv_nested_func2 +GO + +DROP FUNCTION tv_nested_func1 +GO + +DROP TYPE tv_nested_type +GO diff --git a/test/JDBC/expected/table-variable-vu-prepare.out b/test/JDBC/expected/table-variable-vu-prepare.out index a8fa6e5c22..b2851259f0 100644 --- a/test/JDBC/expected/table-variable-vu-prepare.out +++ b/test/JDBC/expected/table-variable-vu-prepare.out @@ -239,3 +239,11 @@ BEGIN RETURN END go + +-- BABEL-4337 - nested TV, null check in tblname +CREATE TYPE tv_nested_type AS TABLE (a INT) +GO +CREATE FUNCTION tv_nested_func1 (@t tv_nested_type readonly) RETURNS @a TABLE (y INT) AS BEGIN; INSERT INTO @a SELECT x FROM @t; RETURN; END; +GO +CREATE FUNCTION tv_nested_func2 (@t tv_nested_type readonly) RETURNS @a TABLE (x INT) AS BEGIN; INSERT INTO @a SELECT y FROM tv_nested_func1(@t); RETURN; END; +GO diff --git a/test/JDBC/expected/table-variable-vu-verify.out b/test/JDBC/expected/table-variable-vu-verify.out index 78e0140388..add8e88fde 100644 --- a/test/JDBC/expected/table-variable-vu-verify.out +++ b/test/JDBC/expected/table-variable-vu-verify.out @@ -68,9 +68,9 @@ Query Text: ASSIGN @a = SELECT 5 Query Text: ASSIGN @b = SELECT 5 Query Text: SELECT 5 -> Result (cost=0.00..0.01 rows=1 width=4) -Query Text: EXEC table_variable_vu_prepareouter_proc @a, @b +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) @@ -84,17 +84,17 @@ 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) -> 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~~ @@ -247,7 +247,6 @@ bit 1 1 1 -1 ~~END~~ @@ -264,3 +263,13 @@ bit 1 ~~END~~ + +-- BABEL-4337 - check nested TV for null; should not crash but throw an error +SELECT * FROM tv_nested_func2(NULL) +go +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: table variable underlying typename is NULL. refname: @t)~~ + diff --git a/test/JDBC/expected/table_variable_xact_basic.out b/test/JDBC/expected/table_variable_xact_basic.out new file mode 100644 index 0000000000..2e0f1d526f --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_basic.out @@ -0,0 +1,807 @@ + +------------------------------------------------------------------------------- +-- High-Level Description: +-- Test basic commit and rollback scenarios with BBF Table Variable. +-- Test BABEL-579, BABEL-3968 scenarios +-- Test Table Variable with Primary Key, Constraint, toast table +-- The results were compared against MS SQL server +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + +------------------------------------------------------------------------------- +-- Test BABEL-579 Use Case 1: Explicit ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +CREATE TYPE tableType AS TABLE(i INT, j INT); +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1,2), (2,1); +ROLLBACK + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#2 +2#!#1 +~~END~~ + +~~START~~ +text +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1,2); + ROLLBACK; + SELECT * FROM @tv; +END +GO + +EXEC rcv_tv3 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +DROP PROCEDURE rcv_tv3 +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1,2), (2,1); +COMMIT TRANSACTION + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#2 +2#!#1 +~~END~~ + +~~START~~ +text +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1,2); + COMMIT; + SELECT * FROM @tv; +END +GO + +DROP PROCEDURE rcv_tv3 +GO + +DROP TYPE tableType +GO + +------------------------------------------------------------------------------- +-- Test BABEL-579 Use Case 3: Error scenario leads to Implicit ROLLBACK +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +GO +~~ROW COUNT: 2~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- Test BABEL-3968 +------------------------------------------------------------------------------- +CREATE TYPE tabvar_type_function_error AS TABLE(a int) +GO + +CREATE PROCEDURE tabvar_select(@tvp tabvar_type_function_error READONLY) AS +BEGIN + SELECT * from @tvp +END +GO + +CREATE FUNCTION f_batch_tran_abort(@tvp tabvar_type_function_error READONLY) +RETURNS smallmoney AS +BEGIN + DECLARE @i smallmoney = 1; + SELECT @i = CAST('ABC' AS SMALLMONEY); + RETURN @i +END +GO + +DECLARE @tvp2 tabvar_type_function_error; +INSERT INTO @tvp2 values (1); +SELECT dbo.f_batch_tran_abort(@tvp2); +GO +~~ROW COUNT: 1~~ + +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: invalid characters found: cannot cast value "ABC" to money)~~ + + +DECLARE @tvp2 tabvar_type_function_error +INSERT INTO @tvp2 values (2) +EXEC tabvar_select @tvp2 +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +text +@tvp2_0 +~~END~~ + + +DROP FUNCTION f_batch_tran_abort +GO + +DROP PROCEDURE tabvar_select +GO + +DROP TYPE tabvar_type_function_error +GO +------------------------------------------------------------------------------- +-- Test 1: Simple INSERT INTO Table Variable with ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +ROLLBACK +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +COMMIT +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 2: DECLARE Table Variable inside a transaction then ROLLBACK +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT) + INSERT INTO @tv4 VALUES(1, 2) +ROLLBACK +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT) + INSERT INTO @tv4 VALUES(1, 2) +COMMIT +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 3: INSERT with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv3 TABLE(c1 INT, c2 INT); +INSERT INTO @tv3 VALUES(1, 2) +BEGIN TRANSACTION + INSERT INTO @tv3 VALUES(2, 3) +COMMIT +SELECT * FROM @tv3 -- should see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 4: INSERT and UPDATE with ROLLBACK. Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv5 TABLE(c1 INT, c2 INT) +INSERT INTO @tv5 VALUES(1, 2) +BEGIN TRANSACTION + UPDATE @tv5 SET c1 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c1 = 100 WHERE c1 = 10 +ROLLBACK +SELECT * FROM @tv5 -- should see (100, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +100#!#2 +~~END~~ + + +DECLARE @tv5 TABLE(c1 INT, c2 INT) +INSERT INTO @tv5 VALUES(1, 2) +BEGIN TRANSACTION + UPDATE @tv5 SET c1 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c1 = 100 WHERE c1 = 10 +COMMIT +SELECT * FROM @tv5 -- should see (100, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +100#!#2 +~~END~~ + + +-- Also test with Identity columns +DECLARE @tv5 TABLE(c1 INT IDENTITY, c2 INT) +INSERT INTO @tv5 VALUES(1) +BEGIN TRANSACTION + UPDATE @tv5 SET c2 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c2 = 100 WHERE c1 = 1 +ROLLBACK +SELECT * FROM @tv5 -- should see (1, 100) +INSERT INTO @tv5 VALUES(2) +SELECT * FROM @tv5 -- should see (2, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +2#!#2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 5: Data with multiple versions +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +ROLLBACK +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + + +-- Repeat with commit then rollback +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +COMMIT +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 6: Table Variable with Primary Key +-- should not show rows inserted by failed transaction +------------------------------------------------------------------------------- +CREATE TYPE tv_table_primary_key AS +TABLE(c1 INT PRIMARY KEY, b INT, c CHAR(15) DEFAULT 'Whoops!') +GO + +DECLARE @tv1 tv_table_primary_key; +INSERT INTO @tv1 VALUES(1, 1, 'First') +INSERT INTO @tv1 VALUES(1, 1, 'Second') -- Heap insert succeeds, index insert fails. +SELECT * FROM @tv1 -- Should only show one record +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_pkey")~~ + +~~START~~ +int#!#int#!#char +1#!#1#!#First +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 7: Primary Key metadata should be accessible after rollback +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 tv_table_primary_key; + INSERT INTO @tv1 VALUES(1, 1, 'First') + INSERT INTO @tv1 VALUES(1, 1, 'Second') -- Heap insert succeeds, index insert fails. +ROLLBACK +INSERT INTO @tv1 VALUES(1, 1, 'Second') -- index still valid. should fail with duplicate key +SELECT * FROM @tv1 -- Should only show one record +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_pkey")~~ + +~~START~~ +int#!#int#!#char +1#!#1#!#First +~~END~~ + + +DROP TYPE tv_table_primary_key +GO +------------------------------------------------------------------------------- +-- Test 8: Similar as above but with Unique Key constraint instead of Primary Key +------------------------------------------------------------------------------- +CREATE TYPE tv_table_constraint AS +TABLE(a VARCHAR(15) UNIQUE NOT NULL, b INT, c CHAR(15) DEFAULT 'Whoops!') +GO + +DECLARE @tv1 tv_table_constraint; +INSERT INTO @tv1 VALUES(1, 1, 'First') +INSERT INTO @tv1 VALUES(2, 2, 'Second') +UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +SELECT * FROM @tv1 -- Should show the two original records +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_a_key")~~ + +~~START~~ +varchar#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +~~END~~ + +~~START~~ +text +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0_a_key +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 9: Unique Key constraint metadata should be accessible after rollback +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 tv_table_constraint; + INSERT INTO @tv1 VALUES(1, 1, 'First') + INSERT INTO @tv1 VALUES(2, 2, 'Second') + UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +ROLLBACK +UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +SELECT * FROM @tv1 -- Should show the two original records +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_a_key")~~ + +~~START~~ +varchar#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +~~END~~ + + +DROP TYPE tv_table_constraint +GO + +------------------------------------------------------------------------------- +-- Test 10: Table Variable with toast table +-- Toast metadata and data should be accessible and valid after ROLLBACK +-- Repeat for COMMITT +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX)); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +ROLLBACK + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX)); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +COMMIT + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 11: Table Variable should be safe from Halloween Problem +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(a INT, b CHAR(256), c VARCHAR(MAX)); + INSERT INTO @tv_toast SELECT GENERATE_SERIES(1, 32, 1), 'Hello', REPLICATE('this is the first record. ', 10000); +ROLLBACK + -- should update 10 records only + UPDATE @tv_toast SET c = 'updated: this is the first record' WHERE a <= 10 + -- explicitly not include ORDER BY to confirm sequence scan order + SELECT a, SUBSTRING(c, 1, 32) FROM @tv_toast +GO +~~ROW COUNT: 32~~ + +~~ROW COUNT: 10~~ + +~~START~~ +int#!#varchar +11#!#this is the first record. this i +12#!#this is the first record. this i +13#!#this is the first record. this i +14#!#this is the first record. this i +15#!#this is the first record. this i +16#!#this is the first record. this i +17#!#this is the first record. this i +18#!#this is the first record. this i +19#!#this is the first record. this i +20#!#this is the first record. this i +21#!#this is the first record. this i +22#!#this is the first record. this i +23#!#this is the first record. this i +24#!#this is the first record. this i +25#!#this is the first record. this i +26#!#this is the first record. this i +27#!#this is the first record. this i +28#!#this is the first record. this i +29#!#this is the first record. this i +30#!#this is the first record. this i +31#!#this is the first record. this i +32#!#this is the first record. this i +1#!#updated: this is the first recor +2#!#updated: this is the first recor +3#!#updated: this is the first recor +4#!#updated: this is the first recor +5#!#updated: this is the first recor +6#!#updated: this is the first recor +7#!#updated: this is the first recor +8#!#updated: this is the first recor +9#!#updated: this is the first recor +10#!#updated: this is the first recor +~~END~~ + + + + + + + +------------------------------------------------------------------------------- +-- Test 12: Table Variable used with OUTPUT clause +------------------------------------------------------------------------------- +CREATE TABLE TestTable (ID INT, TEXTVal VARCHAR(100)) +INSERT TestTable (ID, TEXTVal) VALUES (1,'FirstVal'), (2, 'SecondVal') +BEGIN TRANSACTION +DECLARE @TmpTable TABLE (ID_New INT, TEXTVal_New VARCHAR(100),ID_Old INT, TEXTVal_Old VARCHAR(100)) +UPDATE TestTable SET TEXTVal = 'NewValue' +OUTPUT Inserted.ID, Inserted.TEXTVal, Deleted.ID, Deleted.TEXTVal INTO @TmpTable +WHERE ID IN (1,2) +SELECT * FROM @TmpTable +SELECT * FROM TestTable +ROLLBACK +-- Table Variable should keep values after rollback +SELECT * FROM @TmpTable +SELECT * FROM TestTable +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#NewValue#!#1#!#FirstVal +2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#NewValue +2#!#NewValue +~~END~~ + +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#NewValue#!#1#!#FirstVal +2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#FirstVal +2#!#SecondVal +~~END~~ + + +DROP TABLE TestTable +GO + + + + + + + + + +------------------------------------------------------------------------------- +-- Test 13: Table Variable used with CURSOR +------------------------------------------------------------------------------- +DECLARE @source TABLE(c1 INT, c2 INT) +INSERT INTO @source VALUES(1, 2), (2,3), (4,5), (6,7), (8,9) +DECLARE @target INT +DECLARE cur CURSOR +FOR SELECT c1 FROM @source +FOR UPDATE OF c1 +OPEN cur +FETCH NEXT FROM cur INTO @target +WHILE @@FETCH_STATUS = 0 BEGIN + UPDATE @source set c1 = c1 * 10 WHERE c1 = @target + FETCH NEXT FROM cur INTO @target -- next item +End +-- housekeeping +CLOSE cur +DEALLOCATE cur +SELECT * FROM @source +GO +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#2 +20#!#3 +40#!#5 +60#!#7 +80#!#9 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 14: BABEL-4267 Table Variables with Identity Columns +------------------------------------------------------------------------------- +CREATE TABLE numbers (number INT NOT NULL) +GO + +DECLARE @FirstString nVarchar(255) +DECLARE @PseudoMatrix TABLE(location int identity primary key, c2 int) +SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0, Char(0) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: null character not permitted)~~ + + +DROP TABLE numbers +GO + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO diff --git a/test/JDBC/expected/table_variable_xact_basic_isolation_snapshot.out b/test/JDBC/expected/table_variable_xact_basic_isolation_snapshot.out new file mode 100644 index 0000000000..015aabf263 --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_basic_isolation_snapshot.out @@ -0,0 +1,809 @@ +SET TRANSACTION ISOLATION LEVEL SNAPSHOT + + +------------------------------------------------------------------------------- +-- High-Level Description: +-- Test basic commit and rollback scenarios with BBF Table Variable. +-- Test BABEL-579, BABEL-3968 scenarios +-- Test Table Variable with Primary Key, Constraint, toast table +-- The results were compared against MS SQL server +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +5 +~~END~~ + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + +------------------------------------------------------------------------------- +-- Test BABEL-579 Use Case 1: Explicit ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +CREATE TYPE tableType AS TABLE(i INT, j INT); +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1,2), (2,1); +ROLLBACK + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#2 +2#!#1 +~~END~~ + +~~START~~ +text +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1,2); + ROLLBACK; + SELECT * FROM @tv; +END +GO + +EXEC rcv_tv3 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +DROP PROCEDURE rcv_tv3 +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1,2), (2,1); +COMMIT TRANSACTION + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#2 +2#!#1 +~~END~~ + +~~START~~ +text +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1,2); + COMMIT; + SELECT * FROM @tv; +END +GO + +DROP PROCEDURE rcv_tv3 +GO + +DROP TYPE tableType +GO + +------------------------------------------------------------------------------- +-- Test BABEL-579 Use Case 3: Error scenario leads to Implicit ROLLBACK +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +GO +~~ROW COUNT: 2~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- Test BABEL-3968 +------------------------------------------------------------------------------- +CREATE TYPE tabvar_type_function_error AS TABLE(a int) +GO + +CREATE PROCEDURE tabvar_select(@tvp tabvar_type_function_error READONLY) AS +BEGIN + SELECT * from @tvp +END +GO + +CREATE FUNCTION f_batch_tran_abort(@tvp tabvar_type_function_error READONLY) +RETURNS smallmoney AS +BEGIN + DECLARE @i smallmoney = 1; + SELECT @i = CAST('ABC' AS SMALLMONEY); + RETURN @i +END +GO + +DECLARE @tvp2 tabvar_type_function_error; +INSERT INTO @tvp2 values (1); +SELECT dbo.f_batch_tran_abort(@tvp2); +GO +~~ROW COUNT: 1~~ + +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: invalid characters found: cannot cast value "ABC" to money)~~ + + +DECLARE @tvp2 tabvar_type_function_error +INSERT INTO @tvp2 values (2) +EXEC tabvar_select @tvp2 +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +text +@tvp2_0 +~~END~~ + + +DROP FUNCTION f_batch_tran_abort +GO + +DROP PROCEDURE tabvar_select +GO + +DROP TYPE tabvar_type_function_error +GO +------------------------------------------------------------------------------- +-- Test 1: Simple INSERT INTO Table Variable with ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +ROLLBACK +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +COMMIT +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 2: DECLARE Table Variable inside a transaction then ROLLBACK +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT) + INSERT INTO @tv4 VALUES(1, 2) +ROLLBACK +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT) + INSERT INTO @tv4 VALUES(1, 2) +COMMIT +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 3: INSERT with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv3 TABLE(c1 INT, c2 INT); +INSERT INTO @tv3 VALUES(1, 2) +BEGIN TRANSACTION + INSERT INTO @tv3 VALUES(2, 3) +COMMIT +SELECT * FROM @tv3 -- should see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 4: INSERT and UPDATE with ROLLBACK. Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv5 TABLE(c1 INT, c2 INT) +INSERT INTO @tv5 VALUES(1, 2) +BEGIN TRANSACTION + UPDATE @tv5 SET c1 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c1 = 100 WHERE c1 = 10 +ROLLBACK +SELECT * FROM @tv5 -- should see (100, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +100#!#2 +~~END~~ + + +DECLARE @tv5 TABLE(c1 INT, c2 INT) +INSERT INTO @tv5 VALUES(1, 2) +BEGIN TRANSACTION + UPDATE @tv5 SET c1 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c1 = 100 WHERE c1 = 10 +COMMIT +SELECT * FROM @tv5 -- should see (100, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +100#!#2 +~~END~~ + + +-- Also test with Identity columns +DECLARE @tv5 TABLE(c1 INT IDENTITY, c2 INT) +INSERT INTO @tv5 VALUES(1) +BEGIN TRANSACTION + UPDATE @tv5 SET c2 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c2 = 100 WHERE c1 = 1 +ROLLBACK +SELECT * FROM @tv5 -- should see (1, 100) +INSERT INTO @tv5 VALUES(2) +SELECT * FROM @tv5 -- should see (2, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +2#!#2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 5: Data with multiple versions +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +ROLLBACK +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + + +-- Repeat with commit then rollback +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +COMMIT +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 6: Table Variable with Primary Key +-- should not show rows inserted by failed transaction +------------------------------------------------------------------------------- +CREATE TYPE tv_table_primary_key AS +TABLE(c1 INT PRIMARY KEY, b INT, c CHAR(15) DEFAULT 'Whoops!') +GO + +DECLARE @tv1 tv_table_primary_key; +INSERT INTO @tv1 VALUES(1, 1, 'First') +INSERT INTO @tv1 VALUES(1, 1, 'Second') -- Heap insert succeeds, index insert fails. +SELECT * FROM @tv1 -- Should only show one record +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_pkey")~~ + +~~START~~ +int#!#int#!#char +1#!#1#!#First +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 7: Primary Key metadata should be accessible after rollback +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 tv_table_primary_key; + INSERT INTO @tv1 VALUES(1, 1, 'First') + INSERT INTO @tv1 VALUES(1, 1, 'Second') -- Heap insert succeeds, index insert fails. +ROLLBACK +INSERT INTO @tv1 VALUES(1, 1, 'Second') -- index still valid. should fail with duplicate key +SELECT * FROM @tv1 -- Should only show one record +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_pkey")~~ + +~~START~~ +int#!#int#!#char +1#!#1#!#First +~~END~~ + + +DROP TYPE tv_table_primary_key +GO +------------------------------------------------------------------------------- +-- Test 8: Similar as above but with Unique Key constraint instead of Primary Key +------------------------------------------------------------------------------- +CREATE TYPE tv_table_constraint AS +TABLE(a VARCHAR(15) UNIQUE NOT NULL, b INT, c CHAR(15) DEFAULT 'Whoops!') +GO + +DECLARE @tv1 tv_table_constraint; +INSERT INTO @tv1 VALUES(1, 1, 'First') +INSERT INTO @tv1 VALUES(2, 2, 'Second') +UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +SELECT * FROM @tv1 -- Should show the two original records +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_a_key")~~ + +~~START~~ +varchar#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +~~END~~ + +~~START~~ +text +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0_a_key +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 9: Unique Key constraint metadata should be accessible after rollback +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 tv_table_constraint; + INSERT INTO @tv1 VALUES(1, 1, 'First') + INSERT INTO @tv1 VALUES(2, 2, 'Second') + UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +ROLLBACK +UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +SELECT * FROM @tv1 -- Should show the two original records +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_a_key")~~ + +~~START~~ +varchar#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +~~END~~ + + +DROP TYPE tv_table_constraint +GO + +------------------------------------------------------------------------------- +-- Test 10: Table Variable with toast table +-- Toast metadata and data should be accessible and valid after ROLLBACK +-- Repeat for COMMITT +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX)); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +ROLLBACK + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX)); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +COMMIT + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 11: Table Variable should be safe from Halloween Problem +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(a INT, b CHAR(256), c VARCHAR(MAX)); + INSERT INTO @tv_toast SELECT GENERATE_SERIES(1, 32, 1), 'Hello', REPLICATE('this is the first record. ', 10000); +ROLLBACK + -- should update 10 records only + UPDATE @tv_toast SET c = 'updated: this is the first record' WHERE a <= 10 + -- explicitly not include ORDER BY to confirm sequence scan order + SELECT a, SUBSTRING(c, 1, 32) FROM @tv_toast +GO +~~ROW COUNT: 32~~ + +~~ROW COUNT: 10~~ + +~~START~~ +int#!#varchar +11#!#this is the first record. this i +12#!#this is the first record. this i +13#!#this is the first record. this i +14#!#this is the first record. this i +15#!#this is the first record. this i +16#!#this is the first record. this i +17#!#this is the first record. this i +18#!#this is the first record. this i +19#!#this is the first record. this i +20#!#this is the first record. this i +21#!#this is the first record. this i +22#!#this is the first record. this i +23#!#this is the first record. this i +24#!#this is the first record. this i +25#!#this is the first record. this i +26#!#this is the first record. this i +27#!#this is the first record. this i +28#!#this is the first record. this i +29#!#this is the first record. this i +30#!#this is the first record. this i +31#!#this is the first record. this i +32#!#this is the first record. this i +1#!#updated: this is the first recor +2#!#updated: this is the first recor +3#!#updated: this is the first recor +4#!#updated: this is the first recor +5#!#updated: this is the first recor +6#!#updated: this is the first recor +7#!#updated: this is the first recor +8#!#updated: this is the first recor +9#!#updated: this is the first recor +10#!#updated: this is the first recor +~~END~~ + + + + + + + +------------------------------------------------------------------------------- +-- Test 12: Table Variable used with OUTPUT clause +------------------------------------------------------------------------------- +CREATE TABLE TestTable (ID INT, TEXTVal VARCHAR(100)) +INSERT TestTable (ID, TEXTVal) VALUES (1,'FirstVal'), (2, 'SecondVal') +BEGIN TRANSACTION +DECLARE @TmpTable TABLE (ID_New INT, TEXTVal_New VARCHAR(100),ID_Old INT, TEXTVal_Old VARCHAR(100)) +UPDATE TestTable SET TEXTVal = 'NewValue' +OUTPUT Inserted.ID, Inserted.TEXTVal, Deleted.ID, Deleted.TEXTVal INTO @TmpTable +WHERE ID IN (1,2) +SELECT * FROM @TmpTable +SELECT * FROM TestTable +ROLLBACK +-- Table Variable should keep values after rollback +SELECT * FROM @TmpTable +SELECT * FROM TestTable +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#NewValue#!#1#!#FirstVal +2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#NewValue +2#!#NewValue +~~END~~ + +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#NewValue#!#1#!#FirstVal +2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#FirstVal +2#!#SecondVal +~~END~~ + + +DROP TABLE TestTable +GO + + + + + + + + + +------------------------------------------------------------------------------- +-- Test 13: Table Variable used with CURSOR +------------------------------------------------------------------------------- +DECLARE @source TABLE(c1 INT, c2 INT) +INSERT INTO @source VALUES(1, 2), (2,3), (4,5), (6,7), (8,9) +DECLARE @target INT +DECLARE cur CURSOR +FOR SELECT c1 FROM @source +FOR UPDATE OF c1 +OPEN cur +FETCH NEXT FROM cur INTO @target +WHILE @@FETCH_STATUS = 0 BEGIN + UPDATE @source set c1 = c1 * 10 WHERE c1 = @target + FETCH NEXT FROM cur INTO @target -- next item +End +-- housekeeping +CLOSE cur +DEALLOCATE cur +SELECT * FROM @source +GO +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#2 +20#!#3 +40#!#5 +60#!#7 +80#!#9 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 14: BABEL-4267 Table Variables with Identity Columns +------------------------------------------------------------------------------- +CREATE TABLE numbers (number INT NOT NULL) +GO + +DECLARE @FirstString nVarchar(255) +DECLARE @PseudoMatrix TABLE(location int identity primary key, c2 int) +SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0, Char(0) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: null character not permitted)~~ + + +DROP TABLE numbers +GO + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO diff --git a/test/JDBC/expected/table_variable_xact_basic_xact_abort_on.out b/test/JDBC/expected/table_variable_xact_basic_xact_abort_on.out new file mode 100644 index 0000000000..24899d241b --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_basic_xact_abort_on.out @@ -0,0 +1,779 @@ +SET xact_abort ON + + +------------------------------------------------------------------------------- +-- High-Level Description: +-- Test basic commit and rollback scenarios with BBF Table Variable. +-- Test BABEL-579, BABEL-3968 scenarios +-- Test Table Variable with Primary Key, Constraint, toast table +-- The results were compared against MS SQL server +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + +------------------------------------------------------------------------------- +-- Test BABEL-579 Use Case 1: Explicit ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +CREATE TYPE tableType AS TABLE(i INT, j INT); +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1,2), (2,1); +ROLLBACK + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#2 +2#!#1 +~~END~~ + +~~START~~ +text +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1,2); + ROLLBACK; + SELECT * FROM @tv; +END +GO + +EXEC rcv_tv3 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +DROP PROCEDURE rcv_tv3 +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1,2), (2,1); +COMMIT TRANSACTION + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#2 +2#!#1 +~~END~~ + +~~START~~ +text +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1,2); + COMMIT; + SELECT * FROM @tv; +END +GO + +DROP PROCEDURE rcv_tv3 +GO + +DROP TYPE tableType +GO + +------------------------------------------------------------------------------- +-- Test BABEL-579 Use Case 3: Error scenario leads to Implicit ROLLBACK +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +GO +~~ROW COUNT: 2~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- Test BABEL-3968 +------------------------------------------------------------------------------- +CREATE TYPE tabvar_type_function_error AS TABLE(a int) +GO + +CREATE PROCEDURE tabvar_select(@tvp tabvar_type_function_error READONLY) AS +BEGIN + SELECT * from @tvp +END +GO + +CREATE FUNCTION f_batch_tran_abort(@tvp tabvar_type_function_error READONLY) +RETURNS smallmoney AS +BEGIN + DECLARE @i smallmoney = 1; + SELECT @i = CAST('ABC' AS SMALLMONEY); + RETURN @i +END +GO + +DECLARE @tvp2 tabvar_type_function_error; +INSERT INTO @tvp2 values (1); +SELECT dbo.f_batch_tran_abort(@tvp2); +GO +~~ROW COUNT: 1~~ + +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: invalid characters found: cannot cast value "ABC" to money)~~ + + +DECLARE @tvp2 tabvar_type_function_error +INSERT INTO @tvp2 values (2) +EXEC tabvar_select @tvp2 +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +2 +~~END~~ + +~~START~~ +text +@tvp2_0 +~~END~~ + + +DROP FUNCTION f_batch_tran_abort +GO + +DROP PROCEDURE tabvar_select +GO + +DROP TYPE tabvar_type_function_error +GO +------------------------------------------------------------------------------- +-- Test 1: Simple INSERT INTO Table Variable with ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +ROLLBACK +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +COMMIT +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 2: DECLARE Table Variable inside a transaction then ROLLBACK +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT) + INSERT INTO @tv4 VALUES(1, 2) +ROLLBACK +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT) + INSERT INTO @tv4 VALUES(1, 2) +COMMIT +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 3: INSERT with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv3 TABLE(c1 INT, c2 INT); +INSERT INTO @tv3 VALUES(1, 2) +BEGIN TRANSACTION + INSERT INTO @tv3 VALUES(2, 3) +COMMIT +SELECT * FROM @tv3 -- should see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 4: INSERT and UPDATE with ROLLBACK. Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv5 TABLE(c1 INT, c2 INT) +INSERT INTO @tv5 VALUES(1, 2) +BEGIN TRANSACTION + UPDATE @tv5 SET c1 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c1 = 100 WHERE c1 = 10 +ROLLBACK +SELECT * FROM @tv5 -- should see (100, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +100#!#2 +~~END~~ + + +DECLARE @tv5 TABLE(c1 INT, c2 INT) +INSERT INTO @tv5 VALUES(1, 2) +BEGIN TRANSACTION + UPDATE @tv5 SET c1 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c1 = 100 WHERE c1 = 10 +COMMIT +SELECT * FROM @tv5 -- should see (100, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +100#!#2 +~~END~~ + + +-- Also test with Identity columns +DECLARE @tv5 TABLE(c1 INT IDENTITY, c2 INT) +INSERT INTO @tv5 VALUES(1) +BEGIN TRANSACTION + UPDATE @tv5 SET c2 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c2 = 100 WHERE c1 = 1 +ROLLBACK +SELECT * FROM @tv5 -- should see (1, 100) +INSERT INTO @tv5 VALUES(2) +SELECT * FROM @tv5 -- should see (2, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +2#!#2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 5: Data with multiple versions +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +ROLLBACK +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + + +-- Repeat with commit then rollback +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +COMMIT +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 6: Table Variable with Primary Key +-- should not show rows inserted by failed transaction +------------------------------------------------------------------------------- +CREATE TYPE tv_table_primary_key AS +TABLE(c1 INT PRIMARY KEY, b INT, c CHAR(15) DEFAULT 'Whoops!') +GO + +DECLARE @tv1 tv_table_primary_key; +INSERT INTO @tv1 VALUES(1, 1, 'First') +INSERT INTO @tv1 VALUES(1, 1, 'Second') -- Heap insert succeeds, index insert fails. +SELECT * FROM @tv1 -- Should only show one record +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_pkey")~~ + + +------------------------------------------------------------------------------- +-- Test 7: Primary Key metadata should be accessible after rollback +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 tv_table_primary_key; + INSERT INTO @tv1 VALUES(1, 1, 'First') + INSERT INTO @tv1 VALUES(1, 1, 'Second') -- Heap insert succeeds, index insert fails. +ROLLBACK +INSERT INTO @tv1 VALUES(1, 1, 'Second') -- index still valid. should fail with duplicate key +SELECT * FROM @tv1 -- Should only show one record +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_pkey")~~ + + +DROP TYPE tv_table_primary_key +GO +------------------------------------------------------------------------------- +-- Test 8: Similar as above but with Unique Key constraint instead of Primary Key +------------------------------------------------------------------------------- +CREATE TYPE tv_table_constraint AS +TABLE(a VARCHAR(15) UNIQUE NOT NULL, b INT, c CHAR(15) DEFAULT 'Whoops!') +GO + +DECLARE @tv1 tv_table_constraint; +INSERT INTO @tv1 VALUES(1, 1, 'First') +INSERT INTO @tv1 VALUES(2, 2, 'Second') +UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +SELECT * FROM @tv1 -- Should show the two original records +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_a_key")~~ + + +------------------------------------------------------------------------------- +-- Test 9: Unique Key constraint metadata should be accessible after rollback +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 tv_table_constraint; + INSERT INTO @tv1 VALUES(1, 1, 'First') + INSERT INTO @tv1 VALUES(2, 2, 'Second') + UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +ROLLBACK +UPDATE @tv1 SET a = 1 WHERE a = 2 -- Duplicate Key +SELECT * FROM @tv1 -- Should show the two original records +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv1_0_a_key")~~ + + +DROP TYPE tv_table_constraint +GO + +------------------------------------------------------------------------------- +-- Test 10: Table Variable with toast table +-- Toast metadata and data should be accessible and valid after ROLLBACK +-- Repeat for COMMITT +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX)); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +ROLLBACK + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX)); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +COMMIT + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 11: Table Variable should be safe from Halloween Problem +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(a INT, b CHAR(256), c VARCHAR(MAX)); + INSERT INTO @tv_toast SELECT GENERATE_SERIES(1, 32, 1), 'Hello', REPLICATE('this is the first record. ', 10000); +ROLLBACK + -- should update 10 records only + UPDATE @tv_toast SET c = 'updated: this is the first record' WHERE a <= 10 + -- explicitly not include ORDER BY to confirm sequence scan order + SELECT a, SUBSTRING(c, 1, 32) FROM @tv_toast +GO +~~ROW COUNT: 32~~ + +~~ROW COUNT: 10~~ + +~~START~~ +int#!#varchar +11#!#this is the first record. this i +12#!#this is the first record. this i +13#!#this is the first record. this i +14#!#this is the first record. this i +15#!#this is the first record. this i +16#!#this is the first record. this i +17#!#this is the first record. this i +18#!#this is the first record. this i +19#!#this is the first record. this i +20#!#this is the first record. this i +21#!#this is the first record. this i +22#!#this is the first record. this i +23#!#this is the first record. this i +24#!#this is the first record. this i +25#!#this is the first record. this i +26#!#this is the first record. this i +27#!#this is the first record. this i +28#!#this is the first record. this i +29#!#this is the first record. this i +30#!#this is the first record. this i +31#!#this is the first record. this i +32#!#this is the first record. this i +1#!#updated: this is the first recor +2#!#updated: this is the first recor +3#!#updated: this is the first recor +4#!#updated: this is the first recor +5#!#updated: this is the first recor +6#!#updated: this is the first recor +7#!#updated: this is the first recor +8#!#updated: this is the first recor +9#!#updated: this is the first recor +10#!#updated: this is the first recor +~~END~~ + + + + + + + +------------------------------------------------------------------------------- +-- Test 12: Table Variable used with OUTPUT clause +------------------------------------------------------------------------------- +CREATE TABLE TestTable (ID INT, TEXTVal VARCHAR(100)) +INSERT TestTable (ID, TEXTVal) VALUES (1,'FirstVal'), (2, 'SecondVal') +BEGIN TRANSACTION +DECLARE @TmpTable TABLE (ID_New INT, TEXTVal_New VARCHAR(100),ID_Old INT, TEXTVal_Old VARCHAR(100)) +UPDATE TestTable SET TEXTVal = 'NewValue' +OUTPUT Inserted.ID, Inserted.TEXTVal, Deleted.ID, Deleted.TEXTVal INTO @TmpTable +WHERE ID IN (1,2) +SELECT * FROM @TmpTable +SELECT * FROM TestTable +ROLLBACK +-- Table Variable should keep values after rollback +SELECT * FROM @TmpTable +SELECT * FROM TestTable +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#NewValue#!#1#!#FirstVal +2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#NewValue +2#!#NewValue +~~END~~ + +~~START~~ +int#!#varchar#!#int#!#varchar +1#!#NewValue#!#1#!#FirstVal +2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#FirstVal +2#!#SecondVal +~~END~~ + + +DROP TABLE TestTable +GO + + + + + + + + + +------------------------------------------------------------------------------- +-- Test 13: Table Variable used with CURSOR +------------------------------------------------------------------------------- +DECLARE @source TABLE(c1 INT, c2 INT) +INSERT INTO @source VALUES(1, 2), (2,3), (4,5), (6,7), (8,9) +DECLARE @target INT +DECLARE cur CURSOR +FOR SELECT c1 FROM @source +FOR UPDATE OF c1 +OPEN cur +FETCH NEXT FROM cur INTO @target +WHILE @@FETCH_STATUS = 0 BEGIN + UPDATE @source set c1 = c1 * 10 WHERE c1 = @target + FETCH NEXT FROM cur INTO @target -- next item +End +-- housekeeping +CLOSE cur +DEALLOCATE cur +SELECT * FROM @source +GO +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +10#!#2 +20#!#3 +40#!#5 +60#!#7 +80#!#9 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 14: BABEL-4267 Table Variables with Identity Columns +------------------------------------------------------------------------------- +CREATE TABLE numbers (number INT NOT NULL) +GO + +DECLARE @FirstString nVarchar(255) +DECLARE @PseudoMatrix TABLE(location int identity primary key, c2 int) +SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0, Char(0) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: null character not permitted)~~ + + +DROP TABLE numbers +GO + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO diff --git a/test/JDBC/expected/table_variable_xact_errors.out b/test/JDBC/expected/table_variable_xact_errors.out new file mode 100644 index 0000000000..e1bbdbe15e --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_errors.out @@ -0,0 +1,612 @@ + +-- Test how Table Variables behave during implicit rollback due to error +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 1: Table Variables inside TRY-CATCH block with error +------------------------------------------------------------------------------- +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + SELECT 1 / 0 -- error +END TRY +BEGIN CATCH + BEGIN TRANSACTION + SELECT * FROM @tv -- 3 records + DELETE FROM @tv + ROLLBACK +END CATCH; +-- Table and index should still be accessible here +INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) +UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key +SELECT * FROM @tv -- 3 records +GO +~~ROW COUNT: 3~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_pkey")~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 2: Procedure with Table Variables and THROW +-- Test with PROC + Table Variable and error while relation is open +------------------------------------------------------------------------------- +CREATE PROC table_variable_throw_proc1 AS +BEGIN + DECLARE @tv TABLE (a INT PRIMARY KEY, b CHAR(8)) + INSERT INTO @tv VALUES (1, 'First'); + SELECT * FROM @tv; + THROW 51000, 'Throw error', 1; + INSERT INTO @tv VALUES (2, 'Second'); +END +GO + +EXEC table_variable_throw_proc1 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char +1#!#First +~~END~~ + +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +SELECT * FROM @tv +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tv" does not exist)~~ + + +DROP PROCEDURE table_variable_throw_proc1 +GO + +CREATE PROCEDURE tv_function_1 +AS +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + INSERT INTO @tv VALUES(3, 30) -- duplicate key, fail while table and index are open +END TRY +BEGIN CATCH + INSERT INTO @tv VALUES(3, 30) -- duplicate key, fail while table and index are open + SELECT * FROM @tv +END CATCH; +GO + +EXEC tv_function_1 +GO +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_3_pkey")~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +DROP PROCEDURE tv_function_1 +GO + +------------------------------------------------------------------------------- +-- Test 3: ROLLBACK due to RAISE +------------------------------------------------------------------------------- +CREATE PROCEDURE table_variable_throw_proc1 +AS +BEGIN TRY + DECLARE @tv TABLE (a INT PRIMARY KEY, b CHAR(8)) + INSERT INTO @tv VALUES (1, 'First'); + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + INSERT INTO @tv VALUES (2, 'Second'); + SELECT * FROM @tv; -- return 2 rows + THROW; +END CATCH +GO + +EXEC table_variable_throw_proc1 +GO +~~ROW COUNT: 1~~ + +~~START~~ +varchar +CATCH in Procedure 1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char +1#!#First +2#!#Second +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + + +DROP PROCEDURE table_variable_throw_proc1 +GO + +------------------------------------------------------------------------------- +-- Test 4: Batch termination +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1973-01-01', '1973-11-01'); +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +INSERT INTO @empJobHist VALUES ('1993-01-01', '1993-11-01'); -- should not get here +SELECT * FROM @empJobHist +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +SELECT * FROM @empJobHist +GO +~~ROW COUNT: 2~~ + +~~START~~ +date#!#date +1983-01-01#!#1988-11-01 +1982-11-29#!#1988-06-30 +~~END~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- BABEL-4225: Error inside function should not cause crash +------------------------------------------------------------------------------- +CREATE SCHEMA [Control] +GO + +CREATE FUNCTION [Control].[csf_script_delete_row] ( + @SetIDLocal INT, + @InternalID VARCHAR(64) +) RETURNS VARCHAR(MAX) +AS +BEGIN + DECLARE @Template VARCHAR(MAX); + DECLARE @Results VARCHAR(MAX); + DECLARE @DeletePredicates VARCHAR(MAX); + DECLARE @Ordinal INT; -- NOTE: In this circumstance, each column is either an update or a predicate but not both. + DECLARE @Columns + TABLE ( Ordinal INT IDENTITY(1, 1) NOT NULL, + ColumnPredicate VARCHAR(MAX) NULL, + PRIMARY KEY ( Ordinal ) + ); + SET @Template = 'DELETE [SchemaName].[TableName] WHERE DeleteConditionPredicates;'; + INSERT INTO @Columns (ColumnPredicate ) + SELECT '[' + LRV.ColumnName + '] ' + ISNULL(('= ' + NULLIF(LRV.Expression, 'NULL')), 'IS NULL') + FROM [Control].[DataRow] AS RLR + INNER JOIN [Control].[DataRowValue] AS LRV + ON (RLR.SetID = LRV.SetID AND + RLR.InternalID = LRV.InternalIDRow ) + INNER JOIN [Control].[cvw_local_column_base] AS STC + ON (RLR.SchemaName = STC.SchemaName AND + RLR.TableName = STC.TableName AND + LRV.ColumnName = STC.ColumnName ) + WHERE RLR.SetID = @SetIDLocal + AND RLR.InternalID = @InternalID + AND LRV.MatchType != 'N' + ORDER BY STC.ColumnID ASC;END; -- [Control].[csf_script_delete_row] +go + +SELECT Control.csf_script_delete_row('1', ' ') +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "master_control.datarow" does not exist)~~ + + +DROP FUNCTION [Control].[csf_script_delete_row] +GO + +DROP SCHEMA [Control] +GO + + +------------------------------------------------------------------------------- +-- BABEL-4226: Error while table and index are open. +------------------------------------------------------------------------------- +CREATE FUNCTION dbo.foo() RETURNS @tab TABLE (a INT, b VARCHAR(MAX) NOT NULL) AS +BEGIN + INSERT @tab(a, b) VALUES (1, NULL) + RETURN +END +GO + +SELECT * FROM dbo.foo() +GO +~~START~~ +int#!#varchar +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "b" of relation "@tab_1" violates not-null constraint)~~ + + +DROP FUNCTION dbo.foo() +GO + +CREATE FUNCTION dbo.foo() RETURNS @tab TABLE (a INT PRIMARY KEY, b VARCHAR(MAX) NOT NULL) AS +BEGIN + INSERT @tab(a, b) VALUES (1, NULL) + RETURN +END +GO + +SELECT * FROM dbo.foo() +GO +~~START~~ +int#!#varchar +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "b" of relation "@tab_1" violates not-null constraint)~~ + + +DROP FUNCTION dbo.foo() +GO + +CREATE FUNCTION [dbo].[tv_function_1]() RETURNS @tab TABLE(a int, b int PRIMARY KEY) AS +BEGIN + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + INSERT INTO @tab(a, b) SELECT c1, c2 FROM @tv + INSERT INTO @tab VALUES(4, 30) -- duplicate key, fail while table and index are open + INSERT INTO @tab VALUES(1, 2) + RETURN +END +GO + +SELECT * FROM [dbo].[tv_function_1]() +GO +~~START~~ +int#!#int +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tab_2_pkey")~~ + + +DROP FUNCTION [dbo].[tv_function_1] +GO + + + + +------------------------------------------------------------------------------- +-- BABEL-4227: Error should not cause crash +------------------------------------------------------------------------------- +CREATE FUNCTION LevenschteinDifference +( +@FirstString nVarchar(255), @SecondString nVarchar(255) +) +RETURNS int +as begin +Declare @PseudoMatrix table + (location int identity primary key, + firstorder int not null, + Firstch nchar(1), + secondorder int not null, + Secondch nchar(1), + Thevalue int not null default 0, + PreviousRowValues varchar(200) + ) +insert into @PseudoMatrix (firstorder, firstch, secondorder, secondch, TheValue ) +SELECT TheFirst.number,TheFirst.ch, TheSecond.number,TheSecond.ch,0 + FROM + (SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0,Char(0)) TheFirst + cross JOIN + (SELECT number, SUBSTRING(@SecondString,number,1) AS ch + FROM numbers WHERE number <= LEN(@SecondString) union all Select 0,Char(0)) TheSecond +order by TheFirst.number, TheSecond.number +Declare @current Varchar(255) +Declare @previous Varchar(255) +Declare @TheValue int +Declare @Deletion int, @Insertion int, @Substitution int, @minim int +Select @current='', @previous='' +Update @PseudoMatrix + Set + @Deletion=@TheValue+1, + @Insertion=ascii(substring(@previous,secondorder+1,1))+1, + @Substitution=ascii(substring(@previous,(secondorder),1)) +1, + @minim=case when @Deletion<@Insertion then @Deletion else @insertion end, + @TheValue = Thevalue = case + when SecondOrder=0 then FirstOrder + When FirstOrder=0 then Secondorder + when FirstCh=SecondCh then ascii(substring(@previous,(secondorder),1)) + else case when @Minim<@Substitution then @Minim else @Substitution end + end, + @Previous=PreviousRowValues=case when secondorder =0 then @current else @Previous end, + @current= case when secondorder =0 then char(@TheValue) else @Current+char(@TheValue) end +return @TheValue +End +go + +SELECT dbo.LevenschteinDifference(NULL, NULL) +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "numbers" does not exist)~~ + + +SELECT dbo.LevenschteinDifference(' ', ' ') +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "numbers" does not exist)~~ + + +DROP FUNCTION dbo.LevenschteinDifference +GO + + + +------------------------------------------------------------------------------- +-- Other errors with sp_executesql +------------------------------------------------------------------------------- +CREATE procedure temp_table_sp_exec AS +BEGIN + DECLARE @SQLString NVARCHAR(500); + SET @SQLString = N'declare @table_t1 table(a int); INSERT INTO @table_t1 values(1);SELECT * FROM @table_t1'; + EXECUTE sp_executesql @SQLString; + SET @SQLString = N'declare @table_t1 table(a int NOT NULL); INSERT INTO @table_t1 values(NULL);SELECT * FROM @table_t1'; + EXECUTE sp_executesql @SQLString; +END; +GO + +EXEC temp_table_sp_exec +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "a" of relation "@table_t1_2" violates not-null constraint)~~ + +~~START~~ +int +~~END~~ + + +DROP PROCEDURE temp_table_sp_exec +GO + + +------------------------------------------------------------------------------- +-- Drop type used by table variable +------------------------------------------------------------------------------- +CREATE TYPE typa FROM int +GO + +CREATE TYPE typb FROM nvarchar(100) +GO + + +DECLARE @tv_3 TABLE(a typa, b typb) +DROP TYPE typb +INSERT INTO @tv_3 VALUES(1, 'Hello') +SELECT * FROM @tv_3 +GO +~~ERROR (Code: 3732)~~ + +~~ERROR (Message: cannot drop type typb because other objects depend on it)~~ + + +DROP TYPE typa +GO + +DROP TYPE typb +GO + + + +------------------------------------------------------------------------------- +-- Cursor not explicitly closed +------------------------------------------------------------------------------- +DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) +DECLARE @v INT +DECLARE CUR_NETWORK CURSOR LOCAL FOR SELECT STATION_INT FROM @STATION_INTS_TABLE +OPEN CUR_NETWORK +FETCH NEXT FROM CUR_NETWORK INTO @v +GO + +select 123 +GO +~~START~~ +int +123 +~~END~~ + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) + DECLARE @STATION_INT INT SET @TSQL = '' + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar + +~~END~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) + DECLARE @STATION_INT INT SET @TSQL = '' + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + THROW 51000, 'Throw error', 1; + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT PRIMARY KEY, C2 INT) + DECLARE @STATION_INT INT SET @TSQL = '' + INSERT INTO @STATION_INTS_TABLE VALUES(1, 1) + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE + OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + INSERT INTO @STATION_INTS_TABLE VALUES(1, 1) -- duplicate key + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@station_ints_table_1_pkey")~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + +------------------------------------------------------------------------------- +-- BABEL-4267: Error should not cause crash +------------------------------------------------------------------------------- +CREATE PROCEDURE usp_PopulateDiscount +AS + DECLARE @Lookup TABLE (StartDate DATETIME NOT NULL) + INSERT INTO @Lookup SELECT GETDATE() + BEGIN TRANSACTION + DELETE trgt FROM Discount trgt -- Discount does not exist + COMMIT +go + +EXECUTE usp_PopulateDiscount +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "discount" does not exist)~~ + + +CREATE PROCEDURE test +AS +BEGIN TRY + DECLARE @tv1 TABLE(c1 INT PRIMARY KEY, b INT IDENTITY, c CHAR(15) DEFAULT 'Whoops!') + SELECT 1/0 +END TRY +BEGIN CATCH + BEGIN TRANSACTION + INSERT INTO @tv1 VALUES(1, 3, 'Three') -- invalid syntax, should do a clean shutdown + COMMIT +END CATCH; +GO + +exec test +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: INSERT has more expressions than target columns)~~ + diff --git a/test/JDBC/expected/table_variable_xact_errors_isolation_snapshot.out b/test/JDBC/expected/table_variable_xact_errors_isolation_snapshot.out new file mode 100644 index 0000000000..ba79b81593 --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_errors_isolation_snapshot.out @@ -0,0 +1,622 @@ +SET TRANSACTION ISOLATION LEVEL SNAPSHOT + + +-- Test how Table Variables behave during implicit rollback due to error +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +5 +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 1: Table Variables inside TRY-CATCH block with error +------------------------------------------------------------------------------- +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + SELECT 1 / 0 -- error +END TRY +BEGIN CATCH + BEGIN TRANSACTION + SELECT * FROM @tv -- 3 records + DELETE FROM @tv + ROLLBACK +END CATCH; +-- Table and index should still be accessible here +INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) +UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key +SELECT * FROM @tv -- 3 records +GO +~~ROW COUNT: 3~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_pkey")~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 2: Procedure with Table Variables and THROW +-- Test with PROC + Table Variable and error while relation is open +------------------------------------------------------------------------------- +CREATE PROC table_variable_throw_proc1 AS +BEGIN + DECLARE @tv TABLE (a INT PRIMARY KEY, b CHAR(8)) + INSERT INTO @tv VALUES (1, 'First'); + SELECT * FROM @tv; + THROW 51000, 'Throw error', 1; + INSERT INTO @tv VALUES (2, 'Second'); +END +GO + +EXEC table_variable_throw_proc1 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char +1#!#First +~~END~~ + +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +SELECT * FROM @tv +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tv" does not exist)~~ + + +DROP PROCEDURE table_variable_throw_proc1 +GO + +CREATE PROCEDURE tv_function_1 +AS +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + INSERT INTO @tv VALUES(3, 30) -- duplicate key, fail while table and index are open +END TRY +BEGIN CATCH + INSERT INTO @tv VALUES(3, 30) -- duplicate key, fail while table and index are open + SELECT * FROM @tv +END CATCH; +GO + +EXEC tv_function_1 +GO +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_3_pkey")~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + + +DROP PROCEDURE tv_function_1 +GO + +------------------------------------------------------------------------------- +-- Test 3: ROLLBACK due to RAISE +------------------------------------------------------------------------------- +CREATE PROCEDURE table_variable_throw_proc1 +AS +BEGIN TRY + DECLARE @tv TABLE (a INT PRIMARY KEY, b CHAR(8)) + INSERT INTO @tv VALUES (1, 'First'); + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + INSERT INTO @tv VALUES (2, 'Second'); + SELECT * FROM @tv; -- return 2 rows + THROW; +END CATCH +GO + +EXEC table_variable_throw_proc1 +GO +~~ROW COUNT: 1~~ + +~~START~~ +varchar +CATCH in Procedure 1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char +1#!#First +2#!#Second +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + + +DROP PROCEDURE table_variable_throw_proc1 +GO + +------------------------------------------------------------------------------- +-- Test 4: Batch termination +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1973-01-01', '1973-11-01'); +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +INSERT INTO @empJobHist VALUES ('1993-01-01', '1993-11-01'); -- should not get here +SELECT * FROM @empJobHist +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +SELECT * FROM @empJobHist +GO +~~ROW COUNT: 2~~ + +~~START~~ +date#!#date +1983-01-01#!#1988-11-01 +1982-11-29#!#1988-06-30 +~~END~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- BABEL-4225: Error inside function should not cause crash +------------------------------------------------------------------------------- +CREATE SCHEMA [Control] +GO + +CREATE FUNCTION [Control].[csf_script_delete_row] ( + @SetIDLocal INT, + @InternalID VARCHAR(64) +) RETURNS VARCHAR(MAX) +AS +BEGIN + DECLARE @Template VARCHAR(MAX); + DECLARE @Results VARCHAR(MAX); + DECLARE @DeletePredicates VARCHAR(MAX); + DECLARE @Ordinal INT; -- NOTE: In this circumstance, each column is either an update or a predicate but not both. + DECLARE @Columns + TABLE ( Ordinal INT IDENTITY(1, 1) NOT NULL, + ColumnPredicate VARCHAR(MAX) NULL, + PRIMARY KEY ( Ordinal ) + ); + SET @Template = 'DELETE [SchemaName].[TableName] WHERE DeleteConditionPredicates;'; + INSERT INTO @Columns (ColumnPredicate ) + SELECT '[' + LRV.ColumnName + '] ' + ISNULL(('= ' + NULLIF(LRV.Expression, 'NULL')), 'IS NULL') + FROM [Control].[DataRow] AS RLR + INNER JOIN [Control].[DataRowValue] AS LRV + ON (RLR.SetID = LRV.SetID AND + RLR.InternalID = LRV.InternalIDRow ) + INNER JOIN [Control].[cvw_local_column_base] AS STC + ON (RLR.SchemaName = STC.SchemaName AND + RLR.TableName = STC.TableName AND + LRV.ColumnName = STC.ColumnName ) + WHERE RLR.SetID = @SetIDLocal + AND RLR.InternalID = @InternalID + AND LRV.MatchType != 'N' + ORDER BY STC.ColumnID ASC;END; -- [Control].[csf_script_delete_row] +go + +SELECT Control.csf_script_delete_row('1', ' ') +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "master_control.datarow" does not exist)~~ + + +DROP FUNCTION [Control].[csf_script_delete_row] +GO + +DROP SCHEMA [Control] +GO + + +------------------------------------------------------------------------------- +-- BABEL-4226: Error while table and index are open. +------------------------------------------------------------------------------- +CREATE FUNCTION dbo.foo() RETURNS @tab TABLE (a INT, b VARCHAR(MAX) NOT NULL) AS +BEGIN + INSERT @tab(a, b) VALUES (1, NULL) + RETURN +END +GO + +SELECT * FROM dbo.foo() +GO +~~START~~ +int#!#varchar +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "b" of relation "@tab_1" violates not-null constraint)~~ + + +DROP FUNCTION dbo.foo() +GO + +CREATE FUNCTION dbo.foo() RETURNS @tab TABLE (a INT PRIMARY KEY, b VARCHAR(MAX) NOT NULL) AS +BEGIN + INSERT @tab(a, b) VALUES (1, NULL) + RETURN +END +GO + +SELECT * FROM dbo.foo() +GO +~~START~~ +int#!#varchar +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "b" of relation "@tab_1" violates not-null constraint)~~ + + +DROP FUNCTION dbo.foo() +GO + +CREATE FUNCTION [dbo].[tv_function_1]() RETURNS @tab TABLE(a int, b int PRIMARY KEY) AS +BEGIN + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + INSERT INTO @tab(a, b) SELECT c1, c2 FROM @tv + INSERT INTO @tab VALUES(4, 30) -- duplicate key, fail while table and index are open + INSERT INTO @tab VALUES(1, 2) + RETURN +END +GO + +SELECT * FROM [dbo].[tv_function_1]() +GO +~~START~~ +int#!#int +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tab_2_pkey")~~ + + +DROP FUNCTION [dbo].[tv_function_1] +GO + + + + +------------------------------------------------------------------------------- +-- BABEL-4227: Error should not cause crash +------------------------------------------------------------------------------- +CREATE FUNCTION LevenschteinDifference +( +@FirstString nVarchar(255), @SecondString nVarchar(255) +) +RETURNS int +as begin +Declare @PseudoMatrix table + (location int identity primary key, + firstorder int not null, + Firstch nchar(1), + secondorder int not null, + Secondch nchar(1), + Thevalue int not null default 0, + PreviousRowValues varchar(200) + ) +insert into @PseudoMatrix (firstorder, firstch, secondorder, secondch, TheValue ) +SELECT TheFirst.number,TheFirst.ch, TheSecond.number,TheSecond.ch,0 + FROM + (SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0,Char(0)) TheFirst + cross JOIN + (SELECT number, SUBSTRING(@SecondString,number,1) AS ch + FROM numbers WHERE number <= LEN(@SecondString) union all Select 0,Char(0)) TheSecond +order by TheFirst.number, TheSecond.number +Declare @current Varchar(255) +Declare @previous Varchar(255) +Declare @TheValue int +Declare @Deletion int, @Insertion int, @Substitution int, @minim int +Select @current='', @previous='' +Update @PseudoMatrix + Set + @Deletion=@TheValue+1, + @Insertion=ascii(substring(@previous,secondorder+1,1))+1, + @Substitution=ascii(substring(@previous,(secondorder),1)) +1, + @minim=case when @Deletion<@Insertion then @Deletion else @insertion end, + @TheValue = Thevalue = case + when SecondOrder=0 then FirstOrder + When FirstOrder=0 then Secondorder + when FirstCh=SecondCh then ascii(substring(@previous,(secondorder),1)) + else case when @Minim<@Substitution then @Minim else @Substitution end + end, + @Previous=PreviousRowValues=case when secondorder =0 then @current else @Previous end, + @current= case when secondorder =0 then char(@TheValue) else @Current+char(@TheValue) end +return @TheValue +End +go + +SELECT dbo.LevenschteinDifference(NULL, NULL) +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "numbers" does not exist)~~ + + +SELECT dbo.LevenschteinDifference(' ', ' ') +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "numbers" does not exist)~~ + + +DROP FUNCTION dbo.LevenschteinDifference +GO + + + +------------------------------------------------------------------------------- +-- Other errors with sp_executesql +------------------------------------------------------------------------------- +CREATE procedure temp_table_sp_exec AS +BEGIN + DECLARE @SQLString NVARCHAR(500); + SET @SQLString = N'declare @table_t1 table(a int); INSERT INTO @table_t1 values(1);SELECT * FROM @table_t1'; + EXECUTE sp_executesql @SQLString; + SET @SQLString = N'declare @table_t1 table(a int NOT NULL); INSERT INTO @table_t1 values(NULL);SELECT * FROM @table_t1'; + EXECUTE sp_executesql @SQLString; +END; +GO + +EXEC temp_table_sp_exec +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "a" of relation "@table_t1_2" violates not-null constraint)~~ + +~~START~~ +int +~~END~~ + + +DROP PROCEDURE temp_table_sp_exec +GO + + +------------------------------------------------------------------------------- +-- Drop type used by table variable +------------------------------------------------------------------------------- +CREATE TYPE typa FROM int +GO + +CREATE TYPE typb FROM nvarchar(100) +GO + + +DECLARE @tv_3 TABLE(a typa, b typb) +DROP TYPE typb +INSERT INTO @tv_3 VALUES(1, 'Hello') +SELECT * FROM @tv_3 +GO +~~ERROR (Code: 3732)~~ + +~~ERROR (Message: cannot drop type typb because other objects depend on it)~~ + + +DROP TYPE typa +GO + +DROP TYPE typb +GO + + + +------------------------------------------------------------------------------- +-- Cursor not explicitly closed +------------------------------------------------------------------------------- +DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) +DECLARE @v INT +DECLARE CUR_NETWORK CURSOR LOCAL FOR SELECT STATION_INT FROM @STATION_INTS_TABLE +OPEN CUR_NETWORK +FETCH NEXT FROM CUR_NETWORK INTO @v +GO + +select 123 +GO +~~START~~ +int +123 +~~END~~ + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) + DECLARE @STATION_INT INT SET @TSQL = '' + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar + +~~END~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) + DECLARE @STATION_INT INT SET @TSQL = '' + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + THROW 51000, 'Throw error', 1; + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT PRIMARY KEY, C2 INT) + DECLARE @STATION_INT INT SET @TSQL = '' + INSERT INTO @STATION_INTS_TABLE VALUES(1, 1) + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE + OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + INSERT INTO @STATION_INTS_TABLE VALUES(1, 1) -- duplicate key + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@station_ints_table_1_pkey")~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + +------------------------------------------------------------------------------- +-- BABEL-4267: Error should not cause crash +------------------------------------------------------------------------------- +CREATE PROCEDURE usp_PopulateDiscount +AS + DECLARE @Lookup TABLE (StartDate DATETIME NOT NULL) + INSERT INTO @Lookup SELECT GETDATE() + BEGIN TRANSACTION + DELETE trgt FROM Discount trgt -- Discount does not exist + COMMIT +go +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: function "usp_populatediscount" already exists with same argument types)~~ + + +EXECUTE usp_PopulateDiscount +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "discount" does not exist)~~ + + +CREATE PROCEDURE test +AS +BEGIN TRY + DECLARE @tv1 TABLE(c1 INT PRIMARY KEY, b INT IDENTITY, c CHAR(15) DEFAULT 'Whoops!') + SELECT 1/0 +END TRY +BEGIN CATCH + BEGIN TRANSACTION + INSERT INTO @tv1 VALUES(1, 3, 'Three') -- invalid syntax, should do a clean shutdown + COMMIT +END CATCH; +GO +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: function "test" already exists with same argument types)~~ + + +exec test +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: INSERT has more expressions than target columns)~~ + diff --git a/test/JDBC/expected/table_variable_xact_errors_xact_abort_on.out b/test/JDBC/expected/table_variable_xact_errors_xact_abort_on.out new file mode 100644 index 0000000000..3cc08659ff --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_errors_xact_abort_on.out @@ -0,0 +1,604 @@ +SET xact_abort ON + + +-- Test how Table Variables behave during implicit rollback due to error +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 1: Table Variables inside TRY-CATCH block with error +------------------------------------------------------------------------------- +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + SELECT 1 / 0 -- error +END TRY +BEGIN CATCH + BEGIN TRANSACTION + SELECT * FROM @tv -- 3 records + DELETE FROM @tv + ROLLBACK +END CATCH; +-- Table and index should still be accessible here +INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) +UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key +SELECT * FROM @tv -- 3 records +GO +~~ROW COUNT: 3~~ + +~~START~~ +int#!#int +1#!#10 +2#!#20 +3#!#30 +~~END~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_pkey")~~ + + +------------------------------------------------------------------------------- +-- Test 2: Procedure with Table Variables and THROW +-- Test with PROC + Table Variable and error while relation is open +------------------------------------------------------------------------------- +CREATE PROC table_variable_throw_proc1 AS +BEGIN + DECLARE @tv TABLE (a INT PRIMARY KEY, b CHAR(8)) + INSERT INTO @tv VALUES (1, 'First'); + SELECT * FROM @tv; + THROW 51000, 'Throw error', 1; + INSERT INTO @tv VALUES (2, 'Second'); +END +GO + +EXEC table_variable_throw_proc1 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char +1#!#First +~~END~~ + +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +SELECT * FROM @tv +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tv" does not exist)~~ + + +DROP PROCEDURE table_variable_throw_proc1 +GO + +CREATE PROCEDURE tv_function_1 +AS +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + INSERT INTO @tv VALUES(3, 30) -- duplicate key, fail while table and index are open +END TRY +BEGIN CATCH + INSERT INTO @tv VALUES(3, 30) -- duplicate key, fail while table and index are open + SELECT * FROM @tv +END CATCH; +GO + +EXEC tv_function_1 +GO +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_3_pkey")~~ + + +DROP PROCEDURE tv_function_1 +GO + +------------------------------------------------------------------------------- +-- Test 3: ROLLBACK due to RAISE +------------------------------------------------------------------------------- +CREATE PROCEDURE table_variable_throw_proc1 +AS +BEGIN TRY + DECLARE @tv TABLE (a INT PRIMARY KEY, b CHAR(8)) + INSERT INTO @tv VALUES (1, 'First'); + RAISERROR ('raiserror 16', 16, 1); +END TRY +BEGIN CATCH + SELECT 'CATCH in Procedure 1'; + INSERT INTO @tv VALUES (2, 'Second'); + SELECT * FROM @tv; -- return 2 rows + THROW; +END CATCH +GO + +EXEC table_variable_throw_proc1 +GO +~~ROW COUNT: 1~~ + +~~START~~ +varchar +CATCH in Procedure 1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#char +1#!#First +2#!#Second +~~END~~ + +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: raiserror 16)~~ + + +DROP PROCEDURE table_variable_throw_proc1 +GO + +------------------------------------------------------------------------------- +-- Test 4: Batch termination +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1973-01-01', '1973-11-01'); +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +INSERT INTO @empJobHist VALUES ('1993-01-01', '1993-11-01'); -- should not get here +SELECT * FROM @empJobHist +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +SELECT * FROM @empJobHist +GO +~~ROW COUNT: 2~~ + +~~START~~ +date#!#date +1983-01-01#!#1988-11-01 +1982-11-29#!#1988-06-30 +~~END~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- BABEL-4225: Error inside function should not cause crash +------------------------------------------------------------------------------- +CREATE SCHEMA [Control] +GO + +CREATE FUNCTION [Control].[csf_script_delete_row] ( + @SetIDLocal INT, + @InternalID VARCHAR(64) +) RETURNS VARCHAR(MAX) +AS +BEGIN + DECLARE @Template VARCHAR(MAX); + DECLARE @Results VARCHAR(MAX); + DECLARE @DeletePredicates VARCHAR(MAX); + DECLARE @Ordinal INT; -- NOTE: In this circumstance, each column is either an update or a predicate but not both. + DECLARE @Columns + TABLE ( Ordinal INT IDENTITY(1, 1) NOT NULL, + ColumnPredicate VARCHAR(MAX) NULL, + PRIMARY KEY ( Ordinal ) + ); + SET @Template = 'DELETE [SchemaName].[TableName] WHERE DeleteConditionPredicates;'; + INSERT INTO @Columns (ColumnPredicate ) + SELECT '[' + LRV.ColumnName + '] ' + ISNULL(('= ' + NULLIF(LRV.Expression, 'NULL')), 'IS NULL') + FROM [Control].[DataRow] AS RLR + INNER JOIN [Control].[DataRowValue] AS LRV + ON (RLR.SetID = LRV.SetID AND + RLR.InternalID = LRV.InternalIDRow ) + INNER JOIN [Control].[cvw_local_column_base] AS STC + ON (RLR.SchemaName = STC.SchemaName AND + RLR.TableName = STC.TableName AND + LRV.ColumnName = STC.ColumnName ) + WHERE RLR.SetID = @SetIDLocal + AND RLR.InternalID = @InternalID + AND LRV.MatchType != 'N' + ORDER BY STC.ColumnID ASC;END; -- [Control].[csf_script_delete_row] +go + +SELECT Control.csf_script_delete_row('1', ' ') +GO +~~START~~ +varchar +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "master_control.datarow" does not exist)~~ + + +DROP FUNCTION [Control].[csf_script_delete_row] +GO + +DROP SCHEMA [Control] +GO + + +------------------------------------------------------------------------------- +-- BABEL-4226: Error while table and index are open. +------------------------------------------------------------------------------- +CREATE FUNCTION dbo.foo() RETURNS @tab TABLE (a INT, b VARCHAR(MAX) NOT NULL) AS +BEGIN + INSERT @tab(a, b) VALUES (1, NULL) + RETURN +END +GO + +SELECT * FROM dbo.foo() +GO +~~START~~ +int#!#varchar +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "b" of relation "@tab_1" violates not-null constraint)~~ + + +DROP FUNCTION dbo.foo() +GO + +CREATE FUNCTION dbo.foo() RETURNS @tab TABLE (a INT PRIMARY KEY, b VARCHAR(MAX) NOT NULL) AS +BEGIN + INSERT @tab(a, b) VALUES (1, NULL) + RETURN +END +GO + +SELECT * FROM dbo.foo() +GO +~~START~~ +int#!#varchar +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "b" of relation "@tab_1" violates not-null constraint)~~ + + +DROP FUNCTION dbo.foo() +GO + +CREATE FUNCTION [dbo].[tv_function_1]() RETURNS @tab TABLE(a int, b int PRIMARY KEY) AS +BEGIN + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + INSERT INTO @tab(a, b) SELECT c1, c2 FROM @tv + INSERT INTO @tab VALUES(4, 30) -- duplicate key, fail while table and index are open + INSERT INTO @tab VALUES(1, 2) + RETURN +END +GO + +SELECT * FROM [dbo].[tv_function_1]() +GO +~~START~~ +int#!#int +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tab_2_pkey")~~ + + +DROP FUNCTION [dbo].[tv_function_1] +GO + + + + +------------------------------------------------------------------------------- +-- BABEL-4227: Error should not cause crash +------------------------------------------------------------------------------- +CREATE FUNCTION LevenschteinDifference +( +@FirstString nVarchar(255), @SecondString nVarchar(255) +) +RETURNS int +as begin +Declare @PseudoMatrix table + (location int identity primary key, + firstorder int not null, + Firstch nchar(1), + secondorder int not null, + Secondch nchar(1), + Thevalue int not null default 0, + PreviousRowValues varchar(200) + ) +insert into @PseudoMatrix (firstorder, firstch, secondorder, secondch, TheValue ) +SELECT TheFirst.number,TheFirst.ch, TheSecond.number,TheSecond.ch,0 + FROM + (SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0,Char(0)) TheFirst + cross JOIN + (SELECT number, SUBSTRING(@SecondString,number,1) AS ch + FROM numbers WHERE number <= LEN(@SecondString) union all Select 0,Char(0)) TheSecond +order by TheFirst.number, TheSecond.number +Declare @current Varchar(255) +Declare @previous Varchar(255) +Declare @TheValue int +Declare @Deletion int, @Insertion int, @Substitution int, @minim int +Select @current='', @previous='' +Update @PseudoMatrix + Set + @Deletion=@TheValue+1, + @Insertion=ascii(substring(@previous,secondorder+1,1))+1, + @Substitution=ascii(substring(@previous,(secondorder),1)) +1, + @minim=case when @Deletion<@Insertion then @Deletion else @insertion end, + @TheValue = Thevalue = case + when SecondOrder=0 then FirstOrder + When FirstOrder=0 then Secondorder + when FirstCh=SecondCh then ascii(substring(@previous,(secondorder),1)) + else case when @Minim<@Substitution then @Minim else @Substitution end + end, + @Previous=PreviousRowValues=case when secondorder =0 then @current else @Previous end, + @current= case when secondorder =0 then char(@TheValue) else @Current+char(@TheValue) end +return @TheValue +End +go + +SELECT dbo.LevenschteinDifference(NULL, NULL) +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "numbers" does not exist)~~ + + +SELECT dbo.LevenschteinDifference(' ', ' ') +GO +~~START~~ +int +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "numbers" does not exist)~~ + + +DROP FUNCTION dbo.LevenschteinDifference +GO + + + +------------------------------------------------------------------------------- +-- Other errors with sp_executesql +------------------------------------------------------------------------------- +CREATE procedure temp_table_sp_exec AS +BEGIN + DECLARE @SQLString NVARCHAR(500); + SET @SQLString = N'declare @table_t1 table(a int); INSERT INTO @table_t1 values(1);SELECT * FROM @table_t1'; + EXECUTE sp_executesql @SQLString; + SET @SQLString = N'declare @table_t1 table(a int NOT NULL); INSERT INTO @table_t1 values(NULL);SELECT * FROM @table_t1'; + EXECUTE sp_executesql @SQLString; +END; +GO + +EXEC temp_table_sp_exec +GO +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ERROR (Code: 515)~~ + +~~ERROR (Message: null value in column "a" of relation "@table_t1_2" violates not-null constraint)~~ + + +DROP PROCEDURE temp_table_sp_exec +GO + + +------------------------------------------------------------------------------- +-- Drop type used by table variable +------------------------------------------------------------------------------- +CREATE TYPE typa FROM int +GO + +CREATE TYPE typb FROM nvarchar(100) +GO + + +DECLARE @tv_3 TABLE(a typa, b typb) +DROP TYPE typb +INSERT INTO @tv_3 VALUES(1, 'Hello') +SELECT * FROM @tv_3 +GO +~~ERROR (Code: 3732)~~ + +~~ERROR (Message: cannot drop type typb because other objects depend on it)~~ + + +DROP TYPE typa +GO + +DROP TYPE typb +GO + + + +------------------------------------------------------------------------------- +-- Cursor not explicitly closed +------------------------------------------------------------------------------- +DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) +DECLARE @v INT +DECLARE CUR_NETWORK CURSOR LOCAL FOR SELECT STATION_INT FROM @STATION_INTS_TABLE +OPEN CUR_NETWORK +FETCH NEXT FROM CUR_NETWORK INTO @v +GO + +select 123 +GO +~~START~~ +int +123 +~~END~~ + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) + DECLARE @STATION_INT INT SET @TSQL = '' + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar + +~~END~~ + + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar + +~~END~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT) + DECLARE @STATION_INT INT SET @TSQL = '' + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + THROW 51000, 'Throw error', 1; + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar +~~ERROR (Code: 51000)~~ + +~~ERROR (Message: Throw error)~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + + + + +CREATE FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] () +RETURNS NVARCHAR(MAX) AS +BEGIN + DECLARE @TSQL NVARCHAR(MAX) + DECLARE @STATION_INTS_TABLE TABLE (STATION_INT INT PRIMARY KEY, C2 INT) + DECLARE @STATION_INT INT SET @TSQL = '' + INSERT INTO @STATION_INTS_TABLE VALUES(1, 1) + DECLARE CUR_NETWORK CURSOR LOCAL FOR + SELECT STATION_INT FROM @STATION_INTS_TABLE + OPEN CUR_NETWORK + FETCH NEXT FROM CUR_NETWORK INTO @STATION_INT + INSERT INTO @STATION_INTS_TABLE VALUES(1, 1) -- duplicate key + RETURN @TSQL +END +GO + +SELECT dbo.WOSQL_BuildRevenueDetailOLUQuery() +GO +~~START~~ +nvarchar +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@station_ints_table_1_pkey")~~ + + +DROP FUNCTION [dbo].[WOSQL_BuildRevenueDetailOLUQuery] +GO + + +------------------------------------------------------------------------------- +-- BABEL-4267: Error should not cause crash +------------------------------------------------------------------------------- +CREATE PROCEDURE usp_PopulateDiscount +AS + DECLARE @Lookup TABLE (StartDate DATETIME NOT NULL) + INSERT INTO @Lookup SELECT GETDATE() + BEGIN TRANSACTION + DELETE trgt FROM Discount trgt -- Discount does not exist + COMMIT +go +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: function "usp_populatediscount" already exists with same argument types)~~ + + +EXECUTE usp_PopulateDiscount +go +~~ROW COUNT: 1~~ + +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "discount" does not exist)~~ + + +CREATE PROCEDURE test +AS +BEGIN TRY + DECLARE @tv1 TABLE(c1 INT PRIMARY KEY, b INT IDENTITY, c CHAR(15) DEFAULT 'Whoops!') + SELECT 1/0 +END TRY +BEGIN CATCH + BEGIN TRANSACTION + INSERT INTO @tv1 VALUES(1, 3, 'Three') -- invalid syntax, should do a clean shutdown + COMMIT +END CATCH; +GO +~~ERROR (Code: 2714)~~ + +~~ERROR (Message: function "test" already exists with same argument types)~~ + + +exec test +go +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: INSERT has more expressions than target columns)~~ + diff --git a/test/JDBC/expected/table_variable_xact_nested.out b/test/JDBC/expected/table_variable_xact_nested.out new file mode 100644 index 0000000000..07572e4ee5 --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_nested.out @@ -0,0 +1,714 @@ + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + + +------------------------------------------------------------------------------- +-- Test 1.A: Multiple Savepoints +------------------------------------------------------------------------------- +CREATE FUNCTION table_var_func1(@i INT) +RETURNS INT +AS +BEGIN DECLARE @a AS TABLE(a INT, b INT); +INSERT INTO @a VALUES(1, 2); +RETURN 1; +END; +GO + + + + + + + + + + +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @table2 TABLE (c1 INT PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') -- error duplicate key + SAVE TRANSACTION T3 + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + UPDATE @table2 SET c1 = 10 -- This should only update 1 row + SELECT dbo.table_var_func1(1); + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- should only show one row with c1=10, c2=20 + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should only show one row with c2=20 +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@table2_0_pkey")~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + +DROP FUNCTION table_var_func1 +GO + + +------------------------------------------------------------------------------- +-- Test 1.B: Multiple Savepoints with Identity Columns +------------------------------------------------------------------------------- +CREATE FUNCTION table_var_func1(@i INT) +RETURNS INT +AS +BEGIN DECLARE @a AS TABLE(a INT, b INT); +INSERT INTO @a VALUES(1, 2); +RETURN 1; +END; +GO + + + + + + + + + + +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @table2 TABLE (c1 INT IDENTITY PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') + SAVE TRANSACTION T3 + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + SELECT dbo.table_var_func1(1); + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- show two rows, only c1 is different + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') -- sequence should still be valid + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should show 3 rows +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +1#!#2#!#3#!#savepoint_t2 +2#!#2#!#3#!#savepoint_t2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +1#!#2#!#3#!#savepoint_t2 +2#!#2#!#3#!#savepoint_t2 +3#!#2#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@table2_0_c1_seq +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + +DROP FUNCTION table_var_func1 +GO + + +------------------------------------------------------------------------------- +-- Test 2: Table Variables inside TRY-CATCH block +------------------------------------------------------------------------------- +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT, c3 INT IDENTITY) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key + SELECT * FROM @tv +END TRY +BEGIN CATCH + BEGIN TRANSACTION + DELETE FROM @tv + ROLLBACK +END CATCH; +-- Table, index and sequence should still be accessible here +INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) +UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key +SELECT * FROM @tv -- 3 records +SELECT * FROM enr_view +GO +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_pkey")~~ + +~~START~~ +int#!#int#!#int +1#!#10#!#4 +2#!#20#!#5 +3#!#30#!#6 +~~END~~ + +~~START~~ +text +@tv_0_c3_seq +@tv_0 +@tv_0_pkey +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 3.A: Function P1 has TV and calls Function P2 with TV +-- A Transaction modifies the TV returned by P1 +------------------------------------------------------------------------------- +CREATE FUNCTION table_variable_inner_func (@number INTEGER) +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128)) AS +BEGIN + WITH nums_cte(num1, num2) AS (select 1, 'table_variable_inner_func') + INSERT @result SELECT num1, num2 FROM nums_cte + RETURN +END; +GO + +CREATE FUNCTION table_variable_outer_func() +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128)) AS +BEGIN + INSERT INTO @result SELECT * FROM table_variable_inner_func(1) + RETURN; +END +GO + + + + +BEGIN TRANSACTION + SAVE TRANSACTION Savepoint1 + DECLARE @tvf TABLE(c1 INT PRIMARY KEY, c2 CHAR(128)); + INSERT INTO @tvf SELECT * FROM table_variable_outer_func(); + ROLLBACK TRANSACTION Savepoint1 + INSERT INTO @tvf VALUES(2, 'Inserted by Txn') +ROLLBACK TRANSACTION +INSERT INTO @tvf VALUES(1, 'Duplicate Key') -- Table Variable and its Primary Key should still be valid +SELECT * FROM @tvf +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tvf_0_pkey")~~ + +~~START~~ +int#!#char +1#!#table_variable_inner_func +2#!#Inserted by Txn +~~END~~ + +~~START~~ +text +@tvf_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tvf_0_pkey +~~END~~ + + +SELECT * FROM @tvf -- Table Variable not valid anymore +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tvf" does not exist)~~ + + +DROP FUNCTION table_variable_outer_func +GO + +DROP FUNCTION table_variable_inner_func +GO + + +------------------------------------------------------------------------------- +-- Test 3.B: Function P1 has TV and calls Function P2 with TV +-- A Transaction modifies the TV returned by P1 +------------------------------------------------------------------------------- +CREATE FUNCTION table_variable_inner_func (@number INTEGER) +RETURNS @result TABLE (c1 INT PRIMARY KEY, c2 CHAR(128), c3 INT IDENTITY) AS +BEGIN + WITH nums_cte(num1, num2) AS (select 1, 'table_variable_inner_func') + INSERT @result SELECT num1, num2 FROM nums_cte + RETURN +END; +GO + +CREATE FUNCTION table_variable_outer_func() +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128), c3 INT) AS +BEGIN + INSERT INTO @result SELECT * FROM table_variable_inner_func(1) + RETURN; +END +GO + + + + +BEGIN TRANSACTION + SAVE TRANSACTION Savepoint1 + DECLARE @tvf TABLE(c1 INT PRIMARY KEY, c2 CHAR(128), c3 INT, c4 INT IDENTITY); + INSERT INTO @tvf SELECT * FROM table_variable_outer_func(); + ROLLBACK TRANSACTION Savepoint1 + INSERT INTO @tvf VALUES(2, 'Inserted by Txn', 1) +ROLLBACK TRANSACTION +INSERT INTO @tvf VALUES(1, 'Duplicate Key', 2) -- Table Variable and its Primary Key should still be valid +SELECT * FROM @tvf +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tvf_0_pkey")~~ + +~~START~~ +int#!#char#!#int#!#int +1#!#table_variable_inner_func #!#1#!#1 +2#!#Inserted by Txn #!#1#!#2 +~~END~~ + +~~START~~ +text +@tvf_0_c4_seq +@tvf_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tvf_0_pkey +~~END~~ + + +SELECT * FROM @tvf -- Table Variable not valid anymore +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tvf" does not exist)~~ + + +DROP FUNCTION table_variable_outer_func +GO + +DROP FUNCTION table_variable_inner_func +GO + + +------------------------------------------------------------------------------- +-- Test 4: Table Variables in triggers and procedure +------------------------------------------------------------------------------- +CREATE TABLE MainTable ( + firstname VARCHAR(255), + lastname VARCHAR(255), +); +GO + +CREATE TABLE TableUpdatedByTrigger ( + FULLNAME VARCHAR(255), + XACT_STATUS varchar(255), + SQLIDENTITYCOL [int] IDENTITY(1,1) NOT NULL +) +GO + +-- Keeps track of table variables for each nest level +CREATE TABLE TableVariableTracker( + nestlevel INT, + table_variable_name TEXT +) +GO + + +CREATE TRIGGER UpdateMainTableByTrigger ON MainTable +FOR INSERT AS +BEGIN TRANSACTION + SAVE TRANSACTION S1; + DECLARE @table_variable_in_trigger TABLE(fullname VARCHAR(255), valtype VARCHAR(255)) + INSERT INTO @table_variable_in_trigger SELECT CONCAT(firstname, '_', lastname) ,'commit' FROM INSERTED -- insert first row + INSERT INTO TableUpdatedByTrigger(fullname, xact_status) SELECT fullname, valtype FROM @table_variable_in_trigger; + ROLLBACK TRANSACTION S1; +INSERT INTO @table_variable_in_trigger VALUES('', 'rollback') -- insert second row +INSERT INTO TableUpdatedByTrigger(fullname, xact_status) SELECT fullname, valtype FROM @table_variable_in_trigger; +INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +COMMIT TRANSACTION +GO + +CREATE TRIGGER UpdateTableUpdatedByTrigger ON TableUpdatedByTrigger +FOR INSERT +AS +BEGIN TRANSACTION + SAVE TRANSACTION S1; + DECLARE @table_variable_in_trigger TABLE(fullname VARCHAR(255), valtype VARCHAR(255)) + INSERT INTO @table_variable_in_trigger SELECT fullname,'commit' FROM INSERTED -- insert first row + ROLLBACK TRANSACTION S1; + INSERT INTO @table_variable_in_trigger VALUES('','rollback') -- insert second row +INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +COMMIT TRANSACTION +GO + +CREATE PROCEDURE InsertIntoMainTable(@firstname VARCHAR(255), @lastname VARCHAR(255)) +AS + DECLARE @tv TABLE(first VARCHAR(255), last VARCHAR(255)) + INSERT INTO @tv VALUES(@firstname, @lastname) + INSERT INTO MainTable(firstname, lastname) SELECT first, last FROM @tv + INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +GO + +EXEC InsertIntoMainTable @firstname=N'John', @lastname=N'Doe' +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 3~~ + + +SELECT * FROM MainTable +GO +~~START~~ +varchar#!#varchar +John#!#Doe +~~END~~ + + +SELECT * FROM TableUpdatedByTrigger; -- should show two rows +GO +~~START~~ +varchar#!#varchar#!#int +John_Doe#!#commit#!#2 +#!#rollback#!#3 +~~END~~ + + +SELECT * FROM TableVariableTracker +GO +~~START~~ +int#!#text +3#!#inserted +3#!#deleted +3#!#@table_variable_in_trigger_3 +3#!#@pg_toast_#oid_masked# +3#!#@pg_toast_#oid_masked#_index +2#!#inserted +2#!#deleted +2#!#@table_variable_in_trigger_2 +2#!#@pg_toast_#oid_masked# +2#!#@pg_toast_#oid_masked#_index +1#!#@tv_1 +1#!#@pg_toast_#oid_masked# +1#!#@pg_toast_#oid_masked#_index +~~END~~ + + +DROP TRIGGER UpdateTableUpdatedByTrigger +GO + +DROP TRIGGER UpdateMainTableByTrigger +GO + +DROP TABLE TableVariableTracker +GO + +DROP TABLE TableUpdatedByTrigger +GO + +DROP TABLE MainTable +GO + +DROP PROCEDURE InsertIntoMainTable +GO + + + + + + + + + + + + + + + +------------------------------------------------------------------------------- +-- Test 5: Multiple Savepoints with INSERT INTO SELECT +------------------------------------------------------------------------------- +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @accumulator TABLE (c1 INT, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @accumulator VALUES(1, 1, 1, 'savepoint_t2') + DECLARE @table2 TABLE (c1 INT PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') -- error duplicate key + INSERT INTO @accumulator SELECT * FROM @accumulator -- add second row + SAVE TRANSACTION T3 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 3rd to 4th rows + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + UPDATE @table2 SET c1 = 10 -- This should only update 1 row + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 5th to 8th rows + UPDATE @accumulator SET c1 = c1 + 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 9th to 16th rows + SELECT * FROM @accumulator -- there should be 16 rows + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- should only show one row with c1=10, c2=20 + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should only show one row with c2=20 +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@table2_0_pkey")~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 8~~ + +~~ROW COUNT: 8~~ + +~~START~~ +int#!#int#!#int#!#char +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@accumulator_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO + + diff --git a/test/JDBC/expected/table_variable_xact_nested_2.out b/test/JDBC/expected/table_variable_xact_nested_2.out new file mode 100644 index 0000000000..65095b3557 --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_nested_2.out @@ -0,0 +1,443 @@ +USE master +go + +CREATE DATABASE babel_4263_db +go + +USE babel_4263_db +go + +CREATE SCHEMA babel_4263_schema +go + +CREATE FUNCTION [babel_4263_schema].[babel_4263_fn_DatabaseSelect] (@DatabaseList nvarchar(max)) +RETURNS @Database TABLE(DatabaseName nvarchar(max) NOT NULL) +AS +BEGIN + DECLARE @Database01 TABLE(DatabaseName nvarchar(max), + DatabaseStatus bit) + DECLARE @Database02 TABLE(DatabaseName nvarchar(max), + DatabaseStatus bit) + DECLARE @DatabaseItem nvarchar(max) + DECLARE @Position int + SET @DatabaseList = LTRIM(RTRIM(@DatabaseList)) + SET @DatabaseList = REPLACE(@DatabaseList,' ','') + SET @DatabaseList = REPLACE(@DatabaseList,'[','') + SET @DatabaseList = REPLACE(@DatabaseList,']','') + SET @DatabaseList = REPLACE(@DatabaseList,'''','') + SET @DatabaseList = REPLACE(@DatabaseList,'"','') + WHILE CHARINDEX(',,',@DatabaseList) > 0 SET @DatabaseList = REPLACE(@DatabaseList,',,',',') + IF RIGHT(@DatabaseList,1) = ',' SET @DatabaseList = LEFT(@DatabaseList,LEN(@DatabaseList) - 1) + IF LEFT(@DatabaseList,1) = ',' SET @DatabaseList = RIGHT(@DatabaseList,LEN(@DatabaseList) - 1) + WHILE LEN(@DatabaseList) > 0 + BEGIN + SET @Position = CHARINDEX(',', @DatabaseList) + IF @Position = 0 + BEGIN + SET @DatabaseItem = @DatabaseList + SET @DatabaseList = '' + END + ELSE + BEGIN + SET @DatabaseItem = LEFT(@DatabaseList, @Position - 1) + SET @DatabaseList = RIGHT(@DatabaseList, LEN(@DatabaseList) - @Position) + END + INSERT INTO @Database01 (DatabaseName) VALUES(@DatabaseItem) + END + UPDATE @Database01 + SET DatabaseStatus = 1 + WHERE DatabaseName NOT LIKE '-%' + UPDATE @Database01 + SET DatabaseName = RIGHT(DatabaseName,LEN(DatabaseName) - 1), DatabaseStatus = 0 + WHERE DatabaseName LIKE '-%' + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) + SELECT DISTINCT DatabaseName, DatabaseStatus + FROM @Database01 + WHERE DatabaseName NOT IN('SYSTEM_DATABASES','USER_DATABASES') + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'SYSTEM_DATABASES' AND DatabaseStatus = 0) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('master', 0) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('model', 0) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('msdb', 0) + END + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'SYSTEM_DATABASES' AND DatabaseStatus = 1) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('master', 1) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('model', 1) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('msdb', 1) + END + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'USER_DATABASES' AND DatabaseStatus = 0) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) + SELECT [name], 0 + FROM sys.databases + WHERE database_id > 4 + END + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'USER_DATABASES' AND DatabaseStatus = 1) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) + SELECT [name], 1 + FROM sys.databases + WHERE database_id > 4 + END + INSERT INTO @Database (DatabaseName) + SELECT [name] + FROM sys.databases + WHERE [name] <> 'tempdb' + AND source_database_id IS NULL + INTERSECT + SELECT DatabaseName + FROM @Database02 + WHERE DatabaseStatus = 1 + EXCEPT + SELECT DatabaseName + FROM @Database02 + WHERE DatabaseStatus = 0 + RETURN +END +go + + + + + + + + + +CREATE PROCEDURE [babel_4263_schema].[babel_4263_usp_DatabaseIntegrityCheck] + @Databases nvarchar(max) +AS SET NOCOUNT ON +---------------------------------------------------------------------------------------------------- +--// Declare variables //-- +---------------------------------------------------------------------------------------------------- +DECLARE @StartMessage nvarchar(max) +DECLARE @EndMessage nvarchar(max) +DECLARE @DatabaseMessage nvarchar(max) +DECLARE @ErrorMessage nvarchar(max) +DECLARE @CurrentID int +DECLARE @CurrentDatabase nvarchar(max) +DECLARE @CurrentCommand01 nvarchar(max) +DECLARE @CurrentCommandOutput01 int +DECLARE @tmpDatabases TABLE +( +ID int IDENTITY PRIMARY KEY, +DatabaseName nvarchar(max), +Completed bit +) +DECLARE @Error int +SET @Error = 0 +---------------------------------------------------------------------------------------------------- +--// Log initial information //-- +---------------------------------------------------------------------------------------------------- +SET @StartMessage = 'DateTime: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Server: ' + CAST(SERVERPROPERTY('ServerName') AS nvarchar) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Version: ' + CAST(SERVERPROPERTY('ProductVersion') AS nvarchar) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Edition: ' + CAST(SERVERPROPERTY('Edition') AS nvarchar) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(OBJECT_SCHEMA_NAME(@@PROCID)) + '.' + QUOTENAME(OBJECT_NAME(@@PROCID)) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Parameters: @Databases = ' + ISNULL('''' + REPLACE(@Databases,'''','''''') + '''','NULL') +SET @StartMessage = @StartMessage + CHAR(13) + CHAR(10) +RAISERROR(@StartMessage,10,1) WITH NOWAIT +---------------------------------------------------------------------------------------------------- +--// Select databases //-- +---------------------------------------------------------------------------------------------------- +IF @Databases IS NULL OR @Databases = '' + BEGIN + SET @ErrorMessage = 'The value for parameter @Databases is not supported.' + CHAR(13) + CHAR(10) + RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@ERROR + END +INSERT INTO @tmpDatabases (DatabaseName, Completed) +SELECT DatabaseName AS DatabaseName, 0 AS Completed +FROM babel_4263_schema.babel_4263_fn_DatabaseSelect (@Databases) +ORDER BY DatabaseName ASC +IF @@ERROR <> 0 OR @@ROWCOUNT = 0 + BEGIN + SET @ErrorMessage = 'Error selecting databases.' + CHAR(13) + CHAR(10) + RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@ERROR + END +---------------------------------------------------------------------------------------------------- +--// Check error variable //-- +---------------------------------------------------------------------------------------------------- +IF @Error <> 0 + GOTO Logging +---------------------------------------------------------------------------------------------------- +--// Execute commands //-- +---------------------------------------------------------------------------------------------------- +WHILE EXISTS ( + SELECT * + FROM @tmpDatabases WHERE Completed = 0 + ) + BEGIN + SELECT TOP 1 @CurrentID = ID + , @CurrentDatabase = DatabaseName + FROM @tmpDatabases + WHERE Completed = 0 + ORDER BY ID ASC + -- Set database message + SET @DatabaseMessage = 'DateTime: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) + SET @DatabaseMessage = @DatabaseMessage + 'Database: ' + QUOTENAME(@CurrentDatabase) + CHAR(13) + CHAR(10) + SET @DatabaseMessage = @DatabaseMessage + 'Status: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabase,'status') AS nvarchar) + CHAR(13) + CHAR(10) + RAISERROR(@DatabaseMessage,10,1) WITH NOWAIT + IF DATABASEPROPERTYEX(@CurrentDatabase,'status') = 'ONLINE' + BEGIN + SET @CurrentCommand01 = 'DBCC CHECKDB (' + QUOTENAME(@CurrentDatabase) + ') ' + EXEC sp_executesql @CurrentCommand01 + SET @Error = @@ERROR + IF @Error <> 0 + SET @CurrentCommandOutput01 = @Error + END + -- Update that the database is completed + UPDATE @tmpDatabases + SET Completed = 1 + WHERE ID = @CurrentID + -- Clear variables + SET @CurrentID = NULL + SET @CurrentDatabase = NULL + SET @CurrentCommand01 = NULL + SET @CurrentCommandOutput01 = NULL + RAISERROR('',10,1) WITH NOWAIT + END + ---------------------------------------------------------------------------------------------------- + --// Log completing information //-- + ---------------------------------------------------------------------------------------------------- + Logging: + SET @EndMessage = 'DateTime: ' + CONVERT(nvarchar,GETDATE(),120) + RAISERROR(@EndMessage,10,1) WITH NOWAIT + ---------------------------------------------------------------------------------------------------- GO +go + +EXECUTE babel_4263_schema.babel_4263_usp_DatabaseIntegrityCheck @Databases = NULL +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: The value for parameter @Databases is not supported. +)~~ + + +USE master +go + +DROP DATABASE babel_4263_db +go + +--- +-- Repeat +--- +CREATE DATABASE babel_4263_db +go + +USE babel_4263_db +go + +CREATE SCHEMA babel_4263_schema +go + +CREATE FUNCTION [babel_4263_schema].[babel_4263_fn_DatabaseSelect] (@DatabaseList nvarchar(max)) +RETURNS @Database TABLE(DatabaseName nvarchar(max) NOT NULL) +AS +BEGIN + DECLARE @Database01 TABLE(DatabaseName nvarchar(max), + DatabaseStatus bit) + DECLARE @Database02 TABLE(DatabaseName nvarchar(max), + DatabaseStatus bit) + DECLARE @DatabaseItem nvarchar(max) + DECLARE @Position int + SET @DatabaseList = LTRIM(RTRIM(@DatabaseList)) + SET @DatabaseList = REPLACE(@DatabaseList,' ','') + SET @DatabaseList = REPLACE(@DatabaseList,'[','') + SET @DatabaseList = REPLACE(@DatabaseList,']','') + SET @DatabaseList = REPLACE(@DatabaseList,'''','') + SET @DatabaseList = REPLACE(@DatabaseList,'"','') + WHILE CHARINDEX(',,',@DatabaseList) > 0 SET @DatabaseList = REPLACE(@DatabaseList,',,',',') + IF RIGHT(@DatabaseList,1) = ',' SET @DatabaseList = LEFT(@DatabaseList,LEN(@DatabaseList) - 1) + IF LEFT(@DatabaseList,1) = ',' SET @DatabaseList = RIGHT(@DatabaseList,LEN(@DatabaseList) - 1) + WHILE LEN(@DatabaseList) > 0 + BEGIN + SET @Position = CHARINDEX(',', @DatabaseList) + IF @Position = 0 + BEGIN + SET @DatabaseItem = @DatabaseList + SET @DatabaseList = '' + END + ELSE + BEGIN + SET @DatabaseItem = LEFT(@DatabaseList, @Position - 1) + SET @DatabaseList = RIGHT(@DatabaseList, LEN(@DatabaseList) - @Position) + END + INSERT INTO @Database01 (DatabaseName) VALUES(@DatabaseItem) + END + UPDATE @Database01 + SET DatabaseStatus = 1 + WHERE DatabaseName NOT LIKE '-%' + UPDATE @Database01 + SET DatabaseName = RIGHT(DatabaseName,LEN(DatabaseName) - 1), DatabaseStatus = 0 + WHERE DatabaseName LIKE '-%' + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) + SELECT DISTINCT DatabaseName, DatabaseStatus + FROM @Database01 + WHERE DatabaseName NOT IN('SYSTEM_DATABASES','USER_DATABASES') + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'SYSTEM_DATABASES' AND DatabaseStatus = 0) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('master', 0) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('model', 0) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('msdb', 0) + END + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'SYSTEM_DATABASES' AND DatabaseStatus = 1) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('master', 1) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('model', 1) + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) VALUES('msdb', 1) + END + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'USER_DATABASES' AND DatabaseStatus = 0) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) + SELECT [name], 0 + FROM sys.databases + WHERE database_id > 4 + END + IF EXISTS (SELECT * FROM @Database01 WHERE DatabaseName = 'USER_DATABASES' AND DatabaseStatus = 1) + BEGIN + INSERT INTO @Database02 (DatabaseName, DatabaseStatus) + SELECT [name], 1 + FROM sys.databases + WHERE database_id > 4 + END + INSERT INTO @Database (DatabaseName) + SELECT [name] + FROM sys.databases + WHERE [name] <> 'tempdb' + AND source_database_id IS NULL + INTERSECT + SELECT DatabaseName + FROM @Database02 + WHERE DatabaseStatus = 1 + EXCEPT + SELECT DatabaseName + FROM @Database02 + WHERE DatabaseStatus = 0 + RETURN +END +go + + + + + + + + + +CREATE PROCEDURE [babel_4263_schema].[babel_4263_usp_DatabaseIntegrityCheck] + @Databases nvarchar(max) +AS SET NOCOUNT ON +---------------------------------------------------------------------------------------------------- +--// Declare variables //-- +---------------------------------------------------------------------------------------------------- +DECLARE @StartMessage nvarchar(max) +DECLARE @EndMessage nvarchar(max) +DECLARE @DatabaseMessage nvarchar(max) +DECLARE @ErrorMessage nvarchar(max) +DECLARE @CurrentID int +DECLARE @CurrentDatabase nvarchar(max) +DECLARE @CurrentCommand01 nvarchar(max) +DECLARE @CurrentCommandOutput01 int +DECLARE @tmpDatabases TABLE +( +ID int IDENTITY PRIMARY KEY, +DatabaseName nvarchar(max), +Completed bit +) +DECLARE @Error int +SET @Error = 0 +---------------------------------------------------------------------------------------------------- +--// Log initial information //-- +---------------------------------------------------------------------------------------------------- +SET @StartMessage = 'DateTime: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Server: ' + CAST(SERVERPROPERTY('ServerName') AS nvarchar) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Version: ' + CAST(SERVERPROPERTY('ProductVersion') AS nvarchar) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Edition: ' + CAST(SERVERPROPERTY('Edition') AS nvarchar) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Procedure: ' + QUOTENAME(DB_NAME(DB_ID())) + '.' + QUOTENAME(OBJECT_SCHEMA_NAME(@@PROCID)) + '.' + QUOTENAME(OBJECT_NAME(@@PROCID)) + CHAR(13) + CHAR(10) +SET @StartMessage = @StartMessage + 'Parameters: @Databases = ' + ISNULL('''' + REPLACE(@Databases,'''','''''') + '''','NULL') +SET @StartMessage = @StartMessage + CHAR(13) + CHAR(10) +RAISERROR(@StartMessage,10,1) WITH NOWAIT +---------------------------------------------------------------------------------------------------- +--// Select databases //-- +---------------------------------------------------------------------------------------------------- +IF @Databases IS NULL OR @Databases = '' + BEGIN + SET @ErrorMessage = 'The value for parameter @Databases is not supported.' + CHAR(13) + CHAR(10) + RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@ERROR + END +INSERT INTO @tmpDatabases (DatabaseName, Completed) +SELECT DatabaseName AS DatabaseName, 0 AS Completed +FROM babel_4263_schema.babel_4263_fn_DatabaseSelect (@Databases) +ORDER BY DatabaseName ASC +IF @@ERROR <> 0 OR @@ROWCOUNT = 0 + BEGIN + SET @ErrorMessage = 'Error selecting databases.' + CHAR(13) + CHAR(10) + RAISERROR(@ErrorMessage,16,1) WITH NOWAIT SET @Error = @@ERROR + END +---------------------------------------------------------------------------------------------------- +--// Check error variable //-- +---------------------------------------------------------------------------------------------------- +IF @Error <> 0 + GOTO Logging +---------------------------------------------------------------------------------------------------- +--// Execute commands //-- +---------------------------------------------------------------------------------------------------- +WHILE EXISTS ( + SELECT * + FROM @tmpDatabases WHERE Completed = 0 + ) + BEGIN + SELECT TOP 1 @CurrentID = ID + , @CurrentDatabase = DatabaseName + FROM @tmpDatabases + WHERE Completed = 0 + ORDER BY ID ASC + -- Set database message + SET @DatabaseMessage = 'DateTime: ' + CONVERT(nvarchar,GETDATE(),120) + CHAR(13) + CHAR(10) + SET @DatabaseMessage = @DatabaseMessage + 'Database: ' + QUOTENAME(@CurrentDatabase) + CHAR(13) + CHAR(10) + SET @DatabaseMessage = @DatabaseMessage + 'Status: ' + CAST(DATABASEPROPERTYEX(@CurrentDatabase,'status') AS nvarchar) + CHAR(13) + CHAR(10) + RAISERROR(@DatabaseMessage,10,1) WITH NOWAIT + IF DATABASEPROPERTYEX(@CurrentDatabase,'status') = 'ONLINE' + BEGIN + SET @CurrentCommand01 = 'DBCC CHECKDB (' + QUOTENAME(@CurrentDatabase) + ') ' + EXEC sp_executesql @CurrentCommand01 + SET @Error = @@ERROR + IF @Error <> 0 + SET @CurrentCommandOutput01 = @Error + END + -- Update that the database is completed + UPDATE @tmpDatabases + SET Completed = 1 + WHERE ID = @CurrentID + -- Clear variables + SET @CurrentID = NULL + SET @CurrentDatabase = NULL + SET @CurrentCommand01 = NULL + SET @CurrentCommandOutput01 = NULL + RAISERROR('',10,1) WITH NOWAIT + END + ---------------------------------------------------------------------------------------------------- + --// Log completing information //-- + ---------------------------------------------------------------------------------------------------- + Logging: + SET @EndMessage = 'DateTime: ' + CONVERT(nvarchar,GETDATE(),120) + RAISERROR(@EndMessage,10,1) WITH NOWAIT + ---------------------------------------------------------------------------------------------------- GO +go + +EXECUTE babel_4263_schema.babel_4263_usp_DatabaseIntegrityCheck @Databases = NULL +go +~~ERROR (Code: 50000)~~ + +~~ERROR (Message: The value for parameter @Databases is not supported. +)~~ + + +USE master +go + +DROP DATABASE babel_4263_db +go diff --git a/test/JDBC/expected/table_variable_xact_nested_isolation_snapshot.out b/test/JDBC/expected/table_variable_xact_nested_isolation_snapshot.out new file mode 100644 index 0000000000..fd01243fbf --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_nested_isolation_snapshot.out @@ -0,0 +1,716 @@ +SET TRANSACTION ISOLATION LEVEL SNAPSHOT + + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +5 +~~END~~ + + +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + + +------------------------------------------------------------------------------- +-- Test 1.A: Multiple Savepoints +------------------------------------------------------------------------------- +CREATE FUNCTION table_var_func1(@i INT) +RETURNS INT +AS +BEGIN DECLARE @a AS TABLE(a INT, b INT); +INSERT INTO @a VALUES(1, 2); +RETURN 1; +END; +GO + + + + + + + + + + +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @table2 TABLE (c1 INT PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') -- error duplicate key + SAVE TRANSACTION T3 + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + UPDATE @table2 SET c1 = 10 -- This should only update 1 row + SELECT dbo.table_var_func1(1); + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- should only show one row with c1=10, c2=20 + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should only show one row with c2=20 +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@table2_0_pkey")~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + +DROP FUNCTION table_var_func1 +GO + + +------------------------------------------------------------------------------- +-- Test 1.B: Multiple Savepoints with Identity Columns +------------------------------------------------------------------------------- +CREATE FUNCTION table_var_func1(@i INT) +RETURNS INT +AS +BEGIN DECLARE @a AS TABLE(a INT, b INT); +INSERT INTO @a VALUES(1, 2); +RETURN 1; +END; +GO + + + + + + + + + + +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @table2 TABLE (c1 INT IDENTITY PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') + SAVE TRANSACTION T3 + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + SELECT dbo.table_var_func1(1); + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- show two rows, only c1 is different + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') -- sequence should still be valid + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should show 3 rows +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +1#!#2#!#3#!#savepoint_t2 +2#!#2#!#3#!#savepoint_t2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +1#!#2#!#3#!#savepoint_t2 +2#!#2#!#3#!#savepoint_t2 +3#!#2#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@table2_0_c1_seq +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + +DROP FUNCTION table_var_func1 +GO + + +------------------------------------------------------------------------------- +-- Test 2: Table Variables inside TRY-CATCH block +------------------------------------------------------------------------------- +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT, c3 INT IDENTITY) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key + SELECT * FROM @tv +END TRY +BEGIN CATCH + BEGIN TRANSACTION + DELETE FROM @tv + ROLLBACK +END CATCH; +-- Table, index and sequence should still be accessible here +INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) +UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key +SELECT * FROM @tv -- 3 records +SELECT * FROM enr_view +GO +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_pkey")~~ + +~~START~~ +int#!#int#!#int +1#!#10#!#4 +2#!#20#!#5 +3#!#30#!#6 +~~END~~ + +~~START~~ +text +@tv_0_c3_seq +@tv_0 +@tv_0_pkey +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 3.A: Function P1 has TV and calls Function P2 with TV +-- A Transaction modifies the TV returned by P1 +------------------------------------------------------------------------------- +CREATE FUNCTION table_variable_inner_func (@number INTEGER) +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128)) AS +BEGIN + WITH nums_cte(num1, num2) AS (select 1, 'table_variable_inner_func') + INSERT @result SELECT num1, num2 FROM nums_cte + RETURN +END; +GO + +CREATE FUNCTION table_variable_outer_func() +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128)) AS +BEGIN + INSERT INTO @result SELECT * FROM table_variable_inner_func(1) + RETURN; +END +GO + + + + +BEGIN TRANSACTION + SAVE TRANSACTION Savepoint1 + DECLARE @tvf TABLE(c1 INT PRIMARY KEY, c2 CHAR(128)); + INSERT INTO @tvf SELECT * FROM table_variable_outer_func(); + ROLLBACK TRANSACTION Savepoint1 + INSERT INTO @tvf VALUES(2, 'Inserted by Txn') +ROLLBACK TRANSACTION +INSERT INTO @tvf VALUES(1, 'Duplicate Key') -- Table Variable and its Primary Key should still be valid +SELECT * FROM @tvf +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tvf_0_pkey")~~ + +~~START~~ +int#!#char +1#!#table_variable_inner_func +2#!#Inserted by Txn +~~END~~ + +~~START~~ +text +@tvf_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tvf_0_pkey +~~END~~ + + +SELECT * FROM @tvf -- Table Variable not valid anymore +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tvf" does not exist)~~ + + +DROP FUNCTION table_variable_outer_func +GO + +DROP FUNCTION table_variable_inner_func +GO + + +------------------------------------------------------------------------------- +-- Test 3.B: Function P1 has TV and calls Function P2 with TV +-- A Transaction modifies the TV returned by P1 +------------------------------------------------------------------------------- +CREATE FUNCTION table_variable_inner_func (@number INTEGER) +RETURNS @result TABLE (c1 INT PRIMARY KEY, c2 CHAR(128), c3 INT IDENTITY) AS +BEGIN + WITH nums_cte(num1, num2) AS (select 1, 'table_variable_inner_func') + INSERT @result SELECT num1, num2 FROM nums_cte + RETURN +END; +GO + +CREATE FUNCTION table_variable_outer_func() +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128), c3 INT) AS +BEGIN + INSERT INTO @result SELECT * FROM table_variable_inner_func(1) + RETURN; +END +GO + + + + +BEGIN TRANSACTION + SAVE TRANSACTION Savepoint1 + DECLARE @tvf TABLE(c1 INT PRIMARY KEY, c2 CHAR(128), c3 INT, c4 INT IDENTITY); + INSERT INTO @tvf SELECT * FROM table_variable_outer_func(); + ROLLBACK TRANSACTION Savepoint1 + INSERT INTO @tvf VALUES(2, 'Inserted by Txn', 1) +ROLLBACK TRANSACTION +INSERT INTO @tvf VALUES(1, 'Duplicate Key', 2) -- Table Variable and its Primary Key should still be valid +SELECT * FROM @tvf +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tvf_0_pkey")~~ + +~~START~~ +int#!#char#!#int#!#int +1#!#table_variable_inner_func #!#1#!#1 +2#!#Inserted by Txn #!#1#!#2 +~~END~~ + +~~START~~ +text +@tvf_0_c4_seq +@tvf_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tvf_0_pkey +~~END~~ + + +SELECT * FROM @tvf -- Table Variable not valid anymore +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tvf" does not exist)~~ + + +DROP FUNCTION table_variable_outer_func +GO + +DROP FUNCTION table_variable_inner_func +GO + + +------------------------------------------------------------------------------- +-- Test 4: Table Variables in triggers and procedure +------------------------------------------------------------------------------- +CREATE TABLE MainTable ( + firstname VARCHAR(255), + lastname VARCHAR(255), +); +GO + +CREATE TABLE TableUpdatedByTrigger ( + FULLNAME VARCHAR(255), + XACT_STATUS varchar(255), + SQLIDENTITYCOL [int] IDENTITY(1,1) NOT NULL +) +GO + +-- Keeps track of table variables for each nest level +CREATE TABLE TableVariableTracker( + nestlevel INT, + table_variable_name TEXT +) +GO + + +CREATE TRIGGER UpdateMainTableByTrigger ON MainTable +FOR INSERT AS +BEGIN TRANSACTION + SAVE TRANSACTION S1; + DECLARE @table_variable_in_trigger TABLE(fullname VARCHAR(255), valtype VARCHAR(255)) + INSERT INTO @table_variable_in_trigger SELECT CONCAT(firstname, '_', lastname) ,'commit' FROM INSERTED -- insert first row + INSERT INTO TableUpdatedByTrigger(fullname, xact_status) SELECT fullname, valtype FROM @table_variable_in_trigger; + ROLLBACK TRANSACTION S1; +INSERT INTO @table_variable_in_trigger VALUES('', 'rollback') -- insert second row +INSERT INTO TableUpdatedByTrigger(fullname, xact_status) SELECT fullname, valtype FROM @table_variable_in_trigger; +INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +COMMIT TRANSACTION +GO + +CREATE TRIGGER UpdateTableUpdatedByTrigger ON TableUpdatedByTrigger +FOR INSERT +AS +BEGIN TRANSACTION + SAVE TRANSACTION S1; + DECLARE @table_variable_in_trigger TABLE(fullname VARCHAR(255), valtype VARCHAR(255)) + INSERT INTO @table_variable_in_trigger SELECT fullname,'commit' FROM INSERTED -- insert first row + ROLLBACK TRANSACTION S1; + INSERT INTO @table_variable_in_trigger VALUES('','rollback') -- insert second row +INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +COMMIT TRANSACTION +GO + +CREATE PROCEDURE InsertIntoMainTable(@firstname VARCHAR(255), @lastname VARCHAR(255)) +AS + DECLARE @tv TABLE(first VARCHAR(255), last VARCHAR(255)) + INSERT INTO @tv VALUES(@firstname, @lastname) + INSERT INTO MainTable(firstname, lastname) SELECT first, last FROM @tv + INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +GO + +EXEC InsertIntoMainTable @firstname=N'John', @lastname=N'Doe' +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 3~~ + + +SELECT * FROM MainTable +GO +~~START~~ +varchar#!#varchar +John#!#Doe +~~END~~ + + +SELECT * FROM TableUpdatedByTrigger; -- should show two rows +GO +~~START~~ +varchar#!#varchar#!#int +John_Doe#!#commit#!#2 +#!#rollback#!#3 +~~END~~ + + +SELECT * FROM TableVariableTracker +GO +~~START~~ +int#!#text +3#!#inserted +3#!#deleted +3#!#@table_variable_in_trigger_3 +3#!#@pg_toast_#oid_masked# +3#!#@pg_toast_#oid_masked#_index +2#!#inserted +2#!#deleted +2#!#@table_variable_in_trigger_2 +2#!#@pg_toast_#oid_masked# +2#!#@pg_toast_#oid_masked#_index +1#!#@tv_1 +1#!#@pg_toast_#oid_masked# +1#!#@pg_toast_#oid_masked#_index +~~END~~ + + +DROP TRIGGER UpdateTableUpdatedByTrigger +GO + +DROP TRIGGER UpdateMainTableByTrigger +GO + +DROP TABLE TableVariableTracker +GO + +DROP TABLE TableUpdatedByTrigger +GO + +DROP TABLE MainTable +GO + +DROP PROCEDURE InsertIntoMainTable +GO + + + + + + + + + + + + + + + +------------------------------------------------------------------------------- +-- Test 5: Multiple Savepoints with INSERT INTO SELECT +------------------------------------------------------------------------------- +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @accumulator TABLE (c1 INT, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @accumulator VALUES(1, 1, 1, 'savepoint_t2') + DECLARE @table2 TABLE (c1 INT PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') -- error duplicate key + INSERT INTO @accumulator SELECT * FROM @accumulator -- add second row + SAVE TRANSACTION T3 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 3rd to 4th rows + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + UPDATE @table2 SET c1 = 10 -- This should only update 1 row + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 5th to 8th rows + UPDATE @accumulator SET c1 = c1 + 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 9th to 16th rows + SELECT * FROM @accumulator -- there should be 16 rows + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- should only show one row with c1=10, c2=20 + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should only show one row with c2=20 +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@table2_0_pkey")~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 4~~ + +~~ROW COUNT: 8~~ + +~~ROW COUNT: 8~~ + +~~START~~ +int#!#int#!#int#!#char +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +11#!#1#!#1#!#savepoint_t2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +10#!#20#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@accumulator_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO + + diff --git a/test/JDBC/expected/table_variable_xact_nested_xact_abort_on.out b/test/JDBC/expected/table_variable_xact_nested_xact_abort_on.out new file mode 100644 index 0000000000..713afce2c3 --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_nested_xact_abort_on.out @@ -0,0 +1,545 @@ +SET xact_abort ON + + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + + +------------------------------------------------------------------------------- +-- Test 1.A: Multiple Savepoints +------------------------------------------------------------------------------- +CREATE FUNCTION table_var_func1(@i INT) +RETURNS INT +AS +BEGIN DECLARE @a AS TABLE(a INT, b INT); +INSERT INTO @a VALUES(1, 2); +RETURN 1; +END; +GO + + + + + + + + + + +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @table2 TABLE (c1 INT PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') -- error duplicate key + SAVE TRANSACTION T3 + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + UPDATE @table2 SET c1 = 10 -- This should only update 1 row + SELECT dbo.table_var_func1(1); + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- should only show one row with c1=10, c2=20 + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should only show one row with c2=20 +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@table2_0_pkey")~~ + + +DROP FUNCTION table_var_func1 +GO + + +------------------------------------------------------------------------------- +-- Test 1.B: Multiple Savepoints with Identity Columns +------------------------------------------------------------------------------- +CREATE FUNCTION table_var_func1(@i INT) +RETURNS INT +AS +BEGIN DECLARE @a AS TABLE(a INT, b INT); +INSERT INTO @a VALUES(1, 2); +RETURN 1; +END; +GO + + + + + + + + + + +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @table2 TABLE (c1 INT IDENTITY PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') + SAVE TRANSACTION T3 + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + SELECT dbo.table_var_func1(1); + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- show two rows, only c1 is different + INSERT INTO @table2 VALUES(2, 3, 'savepoint_t2') -- sequence should still be valid + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should show 3 rows +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +1 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int#!#char +1#!#2#!#3#!#savepoint_t2 +2#!#2#!#3#!#savepoint_t2 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#char +1#!#2#!#savepoint_t1 +~~END~~ + +~~START~~ +int#!#int#!#int#!#char +1#!#2#!#3#!#savepoint_t2 +2#!#2#!#3#!#savepoint_t2 +3#!#2#!#3#!#savepoint_t2 +~~END~~ + +~~START~~ +char +savepoint_t3 +~~END~~ + +~~START~~ +text +@table2_0_c1_seq +@table2_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@table2_0_pkey +@tv3_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +@tv1_0 +@pg_toast_#oid_masked# +@pg_toast_#oid_masked#_index +~~END~~ + + +DROP FUNCTION table_var_func1 +GO + + +------------------------------------------------------------------------------- +-- Test 2: Table Variables inside TRY-CATCH block +------------------------------------------------------------------------------- +BEGIN TRY + DECLARE @tv TABLE(c1 INT PRIMARY KEY, c2 INT, c3 INT IDENTITY) + INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) + UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key + SELECT * FROM @tv +END TRY +BEGIN CATCH + BEGIN TRANSACTION + DELETE FROM @tv + ROLLBACK +END CATCH; +-- Table, index and sequence should still be accessible here +INSERT INTO @tv VALUES(1, 10), (2, 20), (3, 30) +UPDATE @tv SET c1 = 1 WHERE c1 = 3 -- duplicate key +SELECT * FROM @tv -- 3 records +SELECT * FROM enr_view +GO +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ROW COUNT: 3~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tv_0_pkey")~~ + + + +------------------------------------------------------------------------------- +-- Test 3.A: Function P1 has TV and calls Function P2 with TV +-- A Transaction modifies the TV returned by P1 +------------------------------------------------------------------------------- +CREATE FUNCTION table_variable_inner_func (@number INTEGER) +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128)) AS +BEGIN + WITH nums_cte(num1, num2) AS (select 1, 'table_variable_inner_func') + INSERT @result SELECT num1, num2 FROM nums_cte + RETURN +END; +GO + +CREATE FUNCTION table_variable_outer_func() +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128)) AS +BEGIN + INSERT INTO @result SELECT * FROM table_variable_inner_func(1) + RETURN; +END +GO + + + + +BEGIN TRANSACTION + SAVE TRANSACTION Savepoint1 + DECLARE @tvf TABLE(c1 INT PRIMARY KEY, c2 CHAR(128)); + INSERT INTO @tvf SELECT * FROM table_variable_outer_func(); + ROLLBACK TRANSACTION Savepoint1 + INSERT INTO @tvf VALUES(2, 'Inserted by Txn') +ROLLBACK TRANSACTION +INSERT INTO @tvf VALUES(1, 'Duplicate Key') -- Table Variable and its Primary Key should still be valid +SELECT * FROM @tvf +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tvf_0_pkey")~~ + + +SELECT * FROM @tvf -- Table Variable not valid anymore +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tvf" does not exist)~~ + + +DROP FUNCTION table_variable_outer_func +GO + +DROP FUNCTION table_variable_inner_func +GO + + +------------------------------------------------------------------------------- +-- Test 3.B: Function P1 has TV and calls Function P2 with TV +-- A Transaction modifies the TV returned by P1 +------------------------------------------------------------------------------- +CREATE FUNCTION table_variable_inner_func (@number INTEGER) +RETURNS @result TABLE (c1 INT PRIMARY KEY, c2 CHAR(128), c3 INT IDENTITY) AS +BEGIN + WITH nums_cte(num1, num2) AS (select 1, 'table_variable_inner_func') + INSERT @result SELECT num1, num2 FROM nums_cte + RETURN +END; +GO + +CREATE FUNCTION table_variable_outer_func() +RETURNS @result TABLE (c1 int PRIMARY KEY, c2 CHAR(128), c3 INT) AS +BEGIN + INSERT INTO @result SELECT * FROM table_variable_inner_func(1) + RETURN; +END +GO + + + + +BEGIN TRANSACTION + SAVE TRANSACTION Savepoint1 + DECLARE @tvf TABLE(c1 INT PRIMARY KEY, c2 CHAR(128), c3 INT, c4 INT IDENTITY); + INSERT INTO @tvf SELECT * FROM table_variable_outer_func(); + ROLLBACK TRANSACTION Savepoint1 + INSERT INTO @tvf VALUES(2, 'Inserted by Txn', 1) +ROLLBACK TRANSACTION +INSERT INTO @tvf VALUES(1, 'Duplicate Key', 2) -- Table Variable and its Primary Key should still be valid +SELECT * FROM @tvf +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@tvf_0_pkey")~~ + + +SELECT * FROM @tvf -- Table Variable not valid anymore +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: relation "@tvf" does not exist)~~ + + +DROP FUNCTION table_variable_outer_func +GO + +DROP FUNCTION table_variable_inner_func +GO + + +------------------------------------------------------------------------------- +-- Test 4: Table Variables in triggers and procedure +------------------------------------------------------------------------------- +CREATE TABLE MainTable ( + firstname VARCHAR(255), + lastname VARCHAR(255), +); +GO + +CREATE TABLE TableUpdatedByTrigger ( + FULLNAME VARCHAR(255), + XACT_STATUS varchar(255), + SQLIDENTITYCOL [int] IDENTITY(1,1) NOT NULL +) +GO + +-- Keeps track of table variables for each nest level +CREATE TABLE TableVariableTracker( + nestlevel INT, + table_variable_name TEXT +) +GO + + +CREATE TRIGGER UpdateMainTableByTrigger ON MainTable +FOR INSERT AS +BEGIN TRANSACTION + SAVE TRANSACTION S1; + DECLARE @table_variable_in_trigger TABLE(fullname VARCHAR(255), valtype VARCHAR(255)) + INSERT INTO @table_variable_in_trigger SELECT CONCAT(firstname, '_', lastname) ,'commit' FROM INSERTED -- insert first row + INSERT INTO TableUpdatedByTrigger(fullname, xact_status) SELECT fullname, valtype FROM @table_variable_in_trigger; + ROLLBACK TRANSACTION S1; +INSERT INTO @table_variable_in_trigger VALUES('', 'rollback') -- insert second row +INSERT INTO TableUpdatedByTrigger(fullname, xact_status) SELECT fullname, valtype FROM @table_variable_in_trigger; +INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +COMMIT TRANSACTION +GO + +CREATE TRIGGER UpdateTableUpdatedByTrigger ON TableUpdatedByTrigger +FOR INSERT +AS +BEGIN TRANSACTION + SAVE TRANSACTION S1; + DECLARE @table_variable_in_trigger TABLE(fullname VARCHAR(255), valtype VARCHAR(255)) + INSERT INTO @table_variable_in_trigger SELECT fullname,'commit' FROM INSERTED -- insert first row + ROLLBACK TRANSACTION S1; + INSERT INTO @table_variable_in_trigger VALUES('','rollback') -- insert second row +INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +COMMIT TRANSACTION +GO + +CREATE PROCEDURE InsertIntoMainTable(@firstname VARCHAR(255), @lastname VARCHAR(255)) +AS + DECLARE @tv TABLE(first VARCHAR(255), last VARCHAR(255)) + INSERT INTO @tv VALUES(@firstname, @lastname) + INSERT INTO MainTable(firstname, lastname) SELECT first, last FROM @tv + INSERT INTO TableVariableTracker SELECT @@NESTLEVEL, relname FROM enr_view +GO + +EXEC InsertIntoMainTable @firstname=N'John', @lastname=N'Doe' +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 2~~ + +~~ROW COUNT: 5~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 3~~ + + +SELECT * FROM MainTable +GO +~~START~~ +varchar#!#varchar +John#!#Doe +~~END~~ + + +SELECT * FROM TableUpdatedByTrigger; -- should show two rows +GO +~~START~~ +varchar#!#varchar#!#int +John_Doe#!#commit#!#2 +#!#rollback#!#3 +~~END~~ + + +SELECT * FROM TableVariableTracker +GO +~~START~~ +int#!#text +3#!#inserted +3#!#deleted +3#!#@table_variable_in_trigger_3 +3#!#@pg_toast_#oid_masked# +3#!#@pg_toast_#oid_masked#_index +2#!#inserted +2#!#deleted +2#!#@table_variable_in_trigger_2 +2#!#@pg_toast_#oid_masked# +2#!#@pg_toast_#oid_masked#_index +1#!#@tv_1 +1#!#@pg_toast_#oid_masked# +1#!#@pg_toast_#oid_masked#_index +~~END~~ + + +DROP TRIGGER UpdateTableUpdatedByTrigger +GO + +DROP TRIGGER UpdateMainTableByTrigger +GO + +DROP TABLE TableVariableTracker +GO + +DROP TABLE TableUpdatedByTrigger +GO + +DROP TABLE MainTable +GO + +DROP PROCEDURE InsertIntoMainTable +GO + + + + + + + + + + + + + + + +------------------------------------------------------------------------------- +-- Test 5: Multiple Savepoints with INSERT INTO SELECT +------------------------------------------------------------------------------- +BEGIN TRANSACTION T1 + SAVE TRANSACTION T2 + DECLARE @accumulator TABLE (c1 INT, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @accumulator VALUES(1, 1, 1, 'savepoint_t2') + DECLARE @table2 TABLE (c1 INT PRIMARY KEY, c2 INT, c3 INT, savepoint_name CHAR(16)) + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') + INSERT INTO @table2 VALUES(1, 2, 3, 'savepoint_t2') -- error duplicate key + INSERT INTO @accumulator SELECT * FROM @accumulator -- add second row + SAVE TRANSACTION T3 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 3rd to 4th rows + DECLARE @tv3 TABLE(savepoint_name CHAR(16)) + INSERT INTO @tv3 VALUES('savepoint_t3') + UPDATE @table2 SET c1 = 10 -- This should only update 1 row + UPDATE @table2 SET c2 = 20 WHERE c1 = 10 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 5th to 8th rows + UPDATE @accumulator SET c1 = c1 + 10 + ROLLBACK TRANSACTION T3 + ROLLBACK TRANSACTION T2 + INSERT INTO @accumulator SELECT * FROM @accumulator -- add 9th to 16th rows + SELECT * FROM @accumulator -- there should be 16 rows + DECLARE @tv1 TABLE(c1 INT, c2 INT, savepoint_name CHAR(16)) + INSERT INTO @tv1 VALUES(1, 2, 'savepoint_t1') + SELECT * FROM @table2; -- should only show one row with c1=10, c2=20 + SELECT * FROM @tv1; +ROLLBACK TRANSACTION T1 +SELECT * FROM @tv1; -- one row inserted even after rollback +SELECT * FROM @table2; -- should only show one row with c2=20 +SELECT * FROM @tv3; -- one row inserted after rollback +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ERROR (Code: 2627)~~ + +~~ERROR (Message: duplicate key value violates unique constraint "@table2_0_pkey")~~ + + + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO + + diff --git a/test/JDBC/expected/table_variable_xact_with_identity.out b/test/JDBC/expected/table_variable_xact_with_identity.out new file mode 100644 index 0000000000..60e7c1ced3 --- /dev/null +++ b/test/JDBC/expected/table_variable_xact_with_identity.out @@ -0,0 +1,628 @@ + +------------------------------------------------------------------------------- +-- High-Level Description: +-- Table Variable Transaction Semantics with Identity columns +------------------------------------------------------------------------------- +SELECT transaction_isolation_level from sys.dm_exec_sessions WHERE session_id = @@SPID +GO +~~START~~ +smallint +2 +~~END~~ + + +------------------------------------------------------------------------------- +-- Setup +------------------------------------------------------------------------------- +CREATE VIEW enr_view AS + SELECT + CASE + WHEN relname LIKE '@pg_toast%' AND relname LIKE '%index%' THEN '@pg_toast_#oid_masked#_index' + WHEN relname LIKE '@pg_toast%' THEN '@pg_toast_#oid_masked#' + ELSE relname + END AS relname + FROM sys.babelfish_get_enr_list() +GO + +------------------------------------------------------------------------------- +-- Test 0: BABEL-4267 Table Variables with Identity Columns +-- Cleanup code when query error should not crash +------------------------------------------------------------------------------- +CREATE TABLE numbers (number INT NOT NULL) +GO + +DECLARE @FirstString nVarchar(255) +DECLARE @PseudoMatrix TABLE(location int identity primary key, c2 int) +SELECT number, SUBSTRING(@FirstString,number,1) AS ch + FROM numbers WHERE number <= LEN(@FirstString) union all Select 0, Char(0) +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: null character not permitted)~~ + + +DROP TABLE numbers +GO + +------------------------------------------------------------------------------- +-- Test 1. Table Variable with Identity Column +-- Explicit ROLLBACK +-- Repeat with COMMIT +------------------------------------------------------------------------------- +CREATE TYPE tableType AS TABLE(i INT IDENTITY, j INT); +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1), (2); +ROLLBACK + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +~~START~~ +text +@tv1_0_i_seq +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1); + ROLLBACK; + SELECT * FROM @tv; +END +GO + +EXEC rcv_tv3 +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#1 +~~END~~ + + +DROP PROCEDURE rcv_tv3 +GO + +DECLARE @tv1 tableType; +BEGIN TRANSACTION + INSERT @tv1 VALUES (1), (2); +COMMIT TRANSACTION + SELECT * FROM @tv1 +SELECT * FROM enr_view +GO +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int +1#!#1 +2#!#2 +~~END~~ + +~~START~~ +text +@tv1_0_i_seq +@tv1_0 +~~END~~ + + +CREATE PROCEDURE rcv_tv3 AS +BEGIN + DECLARE @tv tableType; + BEGIN TRAN; + INSERT INTO @tv values (1); + COMMIT; + SELECT * FROM @tv; +END +GO + +DROP PROCEDURE rcv_tv3 +GO + +DROP TYPE tableType +GO + +------------------------------------------------------------------------------- +-- Test 2: Error scenario leads to Implicit ROLLBACK +------------------------------------------------------------------------------- +CREATE TYPE empDates AS TABLE (start_date DATE, end_date DATE, c3 INT IDENTITY); +GO + +DECLARE @empJobHist empDates; +INSERT INTO @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988', '1988-06-30'); +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: VALUES lists must all be the same length)~~ + + +DECLARE @empJobHist empDates; +insert into @empJobHist VALUES ('1983-01-01', '1988-11-01'), ('1982-11-29', '1988-06-30'); +GO +~~ROW COUNT: 2~~ + + +DROP TYPE empDates +GO + +------------------------------------------------------------------------------- +-- Test 3: Error inside function where Table Variable has Identity +------------------------------------------------------------------------------- +CREATE TYPE tabvar_type_function_error AS TABLE(a int IDENTITY, b int) +GO + +CREATE PROCEDURE tabvar_select(@tvp tabvar_type_function_error READONLY) AS +BEGIN + SELECT * from @tvp +END +GO + +CREATE FUNCTION f_batch_tran_abort(@tvp tabvar_type_function_error READONLY) +RETURNS smallmoney AS +BEGIN + DECLARE @i smallmoney = 1; + SELECT @i = CAST('ABC' AS SMALLMONEY); + RETURN @i +END +GO + +DECLARE @tvp2 tabvar_type_function_error; +INSERT INTO @tvp2 values (1); +SELECT dbo.f_batch_tran_abort(@tvp2); +GO +~~ROW COUNT: 1~~ + +~~START~~ +smallmoney +~~ERROR (Code: 293)~~ + +~~ERROR (Message: invalid characters found: cannot cast value "ABC" to money)~~ + + +DECLARE @tvp2 tabvar_type_function_error +INSERT INTO @tvp2 values (2) +EXEC tabvar_select @tvp2 +SELECT * FROM enr_view +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +~~END~~ + +~~START~~ +text +@tvp2_0_a_seq +@tvp2_0 +~~END~~ + + +DROP FUNCTION f_batch_tran_abort +GO + +DROP PROCEDURE tabvar_select +GO + +DROP TYPE tabvar_type_function_error +GO +------------------------------------------------------------------------------- +-- Test 4: Simple INSERT INTO Table Variable with Identity +-- Test with ROLLBACK and Repeat with COMMIT +------------------------------------------------------------------------------- +DECLARE @tv2 TABLE(c1 INT, c2 INT, c3 INT PRIMARY KEY); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +ROLLBACK +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ERROR (Code: 33557097)~~ + +~~ERROR (Message: Number of given values does not match target table definition)~~ + + +DECLARE @tv2 TABLE(c1 INT, c2 INT); +INSERT INTO @tv2 VALUES(1, 2); +BEGIN TRANSACTION + INSERT INTO @tv2 VALUES(2, 3); + SELECT * FROM @tv2 -- should see 2 rows + SELECT * FROM @tv2 -- repeat when hint bits are set +COMMIT +SELECT * FROM @tv2 -- should still see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + +~~START~~ +int#!#int +1#!#2 +2#!#3 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 5: DECLARE Table Variable inside a transaction then ROLLBACK +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT, c3 INT IDENTITY) + INSERT INTO @tv4 VALUES(1, 2) +ROLLBACK +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int +1#!#2#!#1 +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv4 TABLE(c1 INT, c2 INT, c3 INT IDENTITY) + INSERT INTO @tv4 VALUES(1, 2) +COMMIT +SELECT * FROM @tv4 -- tv4 accessible and should see 1 row +GO +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int +1#!#2#!#1 +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 6: DECLARE Table Variable OUTside a transaction then, do DML then ROLLBACK +------------------------------------------------------------------------------- +DECLARE @tv3 TABLE(c1 INT, c2 INT, c3 INT IDENTITY); +INSERT INTO @tv3 VALUES(1, 2) +BEGIN TRANSACTION + INSERT INTO @tv3 VALUES(2, 3) +COMMIT +SELECT * FROM @tv3 -- should see 2 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#int +1#!#2#!#1 +2#!#3#!#2 +~~END~~ + + +DECLARE @tv5 TABLE(c1 INT IDENTITY, c2 INT) +INSERT INTO @tv5 VALUES(1) +BEGIN TRANSACTION + UPDATE @tv5 SET c2 = 10 WHERE c1 = 1 + UPDATE @tv5 SET c2 = 100 WHERE c1 = 1 +ROLLBACK +SELECT * FROM @tv5 -- should see (1, 100) +INSERT INTO @tv5 VALUES(2) +SELECT * FROM @tv5 -- should see (1, 100), (2, 2) +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int +1#!#100 +2#!#2 +~~END~~ + + + +------------------------------------------------------------------------------- +-- Test 7: Data with multiple versions +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT, c3 INT IDENTITY); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +ROLLBACK +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + + +-- Repeat with commit then rollback +BEGIN TRANSACTION + DECLARE @tv1 TABLE(c1 INT, c2 INT, c3 INT IDENTITY); + INSERT INTO @tv1 VALUES (1, 2); + UPDATE @tv1 SET c1 = 10 WHERE c1 = 1; + UPDATE @tv1 SET c1 = 100 WHERE c1 = 10; +COMMIT +BEGIN TRANSACTION + SELECT c1 FROM @tv1 -- UPDATE operation still valid + DELETE FROM @tv1 WHERE c1 = 1; -- no rows affected + DELETE FROM @tv1 WHERE c1=100 -- 1 row affected +ROLLBACK; + SELECT c1 FROM @tv1 -- DELETE operation still valid +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +100 +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int +~~END~~ + + +------------------------------------------------------------------------------- +-- Test 8: Table Variable with Identity And Primary Key +-- should not show rows inserted by failed transaction +------------------------------------------------------------------------------- +CREATE TYPE tv_table_primary_key AS +TABLE(c1 INT PRIMARY KEY, b INT IDENTITY, c CHAR(15) DEFAULT 'Whoops!') +GO + +BEGIN TRY + DECLARE @tv1 tv_table_primary_key; + INSERT INTO @tv1 VALUES(1, 'First') + INSERT INTO @tv1 VALUES(2, 'Second') + UPDATE @tv1 SET c1=1 WHERE c1=2 -- Heap insert succeeds, index insert fails. +END TRY +BEGIN CATCH + BEGIN TRANSACTION + SELECT * FROM @tv1 -- should not have any duplicates + INSERT INTO @tv1 VALUES(3, 'Three') -- Index, Identity should be valid + ROLLBACK +END CATCH; +SELECT * FROM @tv1 -- should be able to see all 3 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +3#!#3#!#Three +~~END~~ + + +DROP TYPE tv_table_primary_key +GO +------------------------------------------------------------------------------- +-- Test 9: Similar as above but with Unique Key constraint instead of Primary Key +------------------------------------------------------------------------------- +CREATE TYPE tv_table_constraint AS +TABLE(c1 VARCHAR(15) UNIQUE NOT NULL, b INT IDENTITY, c CHAR(15) DEFAULT 'Whoops!') +GO + +BEGIN TRY + DECLARE @tv1 tv_table_constraint; + INSERT INTO @tv1 VALUES(1, 'First') + INSERT INTO @tv1 VALUES(2, 'Second') + UPDATE @tv1 SET c1=1 WHERE c1=2 -- Heap insert succeeds, index insert fails. +END TRY +BEGIN CATCH + BEGIN TRANSACTION + SELECT * FROM @tv1 -- should not have any duplicates + INSERT INTO @tv1 VALUES(3, 'Three') -- Index, Identity should be valid + ROLLBACK +END CATCH; +SELECT * FROM @tv1 -- should be able to see all 3 rows +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +varchar#!#int#!#char +1#!#1#!#First +2#!#2#!#Second +3#!#3#!#Three +~~END~~ + + +DROP TYPE tv_table_constraint +GO + +------------------------------------------------------------------------------- +-- Test 10: Table Variable with toast table and Identity Column +-- Toast metadata and data should be accessible and valid after ROLLBACK +-- Repeat for COMMITT +------------------------------------------------------------------------------- +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX), c3 INT IDENTITY); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +ROLLBACK + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + +BEGIN TRANSACTION + DECLARE @tv_toast TABLE(i INT, v VARCHAR(MAX), c3 INT IDENTITY); + INSERT INTO @tv_toast VALUES (1, REPLICATE('this is the first record. ', 10000)); +COMMIT + INSERT INTO @tv_toast VALUES (2, REPLICATE('this is the second record. ', 10000)); -- toast relation should be accessible + UPDATE @tv_toast SET v = REPLICATE('this is the updated second record. ', 10000) WHERE i = 2 + SELECT i, SUBSTRING(v, 1, 64) FROM @tv_toast ORDER BY i +GO +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#varchar +1#!#this is the first record. this is the first record. this is the +2#!#this is the updated second record. this is the updated second re +~~END~~ + + + + + + + + +------------------------------------------------------------------------------- +-- Test 12: Table Variable used with OUTPUT clause +------------------------------------------------------------------------------- +CREATE TABLE TestTable (ID INT, TEXTVal VARCHAR(100)) +INSERT TestTable (ID, TEXTVal) VALUES (1,'FirstVal'), (2, 'SecondVal') +BEGIN TRANSACTION +DECLARE @TmpTable TABLE (c1 INT IDENTITY, ID_New INT, TEXTVal_New VARCHAR(100), ID_Old INT, TEXTVal_Old VARCHAR(100)) +UPDATE TestTable SET TEXTVal = 'NewValue' +OUTPUT Inserted.ID, Inserted.TEXTVal, Deleted.ID, Deleted.TEXTVal INTO @TmpTable +WHERE ID IN (1,2) +SELECT * FROM @TmpTable +SELECT * FROM TestTable +ROLLBACK +-- Table Variable should keep values after rollback +SELECT * FROM @TmpTable +SELECT * FROM TestTable +-- should be able to do DML +INSERT @TmpTable VALUES (3,'ThirdVal', 3, 'ThirdVal') +SELECT * FROM @TmpTable +GO +~~ROW COUNT: 2~~ + +~~ROW COUNT: 2~~ + +~~START~~ +int#!#int#!#varchar#!#int#!#varchar +1#!#1#!#NewValue#!#1#!#FirstVal +2#!#2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#NewValue +2#!#NewValue +~~END~~ + +~~START~~ +int#!#int#!#varchar#!#int#!#varchar +1#!#1#!#NewValue#!#1#!#FirstVal +2#!#2#!#NewValue#!#2#!#SecondVal +~~END~~ + +~~START~~ +int#!#varchar +1#!#FirstVal +2#!#SecondVal +~~END~~ + +~~ROW COUNT: 1~~ + +~~START~~ +int#!#int#!#varchar#!#int#!#varchar +1#!#1#!#NewValue#!#1#!#FirstVal +2#!#2#!#NewValue#!#2#!#SecondVal +3#!#3#!#ThirdVal#!#3#!#ThirdVal +~~END~~ + + +DROP TABLE TestTable +GO + +------------------------------------------------------------------------------- +-- Cleanup +------------------------------------------------------------------------------- +DROP VIEW enr_view +GO diff --git a/test/JDBC/expected/test_windows_alter_user-vu-verify.out b/test/JDBC/expected/test_windows_alter_user-vu-verify.out index 6043f323a0..4dd4f9a65f 100644 --- a/test/JDBC/expected/test_windows_alter_user-vu-verify.out +++ b/test/JDBC/expected/test_windows_alter_user-vu-verify.out @@ -33,19 +33,15 @@ master_alter_user_test#!#alter_user@BBF#!#dbo ~~END~~ --- negative test cases alter user alter_user_test with login = [bbf\alter_user2]; GO -~~ERROR (Code: 33557097)~~ - -~~ERROR (Message: 'ALTER USER WITH LOGIN' is not currently supported in Babelfish)~~ - +-- negative test cases alter user alter_user_test with password = 123; GO ~~ERROR (Code: 33557097)~~ -~~ERROR (Message: syntax error near '123' at line 1 and character position 43)~~ +~~ERROR (Message: syntax error near '123' at line 2 and character position 43)~~ alter user alter_user_test with default_language = English; 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 [